0%

atomic原子操作

在没有实现无锁化编程之前,我们对共享数据(变量)的操作需要用到锁。多线程并发访问数据的时候,锁的维护非常的麻烦,并且锁的申请和释放、多线程竞争锁的过程中会存在资源的消耗。同时,锁的引入也会引起线程阻塞、锁竞争、死锁等问题。

CAS (compare and swap, CAS) 比较并交换,是原子操作的一种,可用于在多线程编程环境中实现不被打断的数据交换操作,从而避免多线程同时改写某一数据时由于执行顺序不确定性以及终端的不可预知性产生的数据不一致的问题。该操作通过将内存中的值与指定的数据进行交换,当数值一样时将内存中的数据替换为新的值。

一个CAS操作等价于以下C代码的原子实现如下:

1
2
3
4
5
6
7
8
9
int cas(long *addr, long old, long new)
{
/* Executes atomically. */
if( *addr != old ) {
return 0;
}
*addr = new;
return 1;
}

在使用上,通常会记录下某块内存中的旧值,通过对旧值进行一系列的操作后得到新值,然后通过CAS操作将新值与旧值进行交换,如果这块内存的值在这期间内没有被修改过,则旧值会与内存中的数据相同,这是CAS操作将会成功执行使得内存中的数据变为新值。如果内存中的值在这期间内被修改过,则一般来说旧值会与内存中的数据不同,这时,CAS操作将会失败,新值将不会被写入内存中。

GCC 编译器内置了一些内建的原子操作函数,我们不需要使用其他的库就可以简单的进行一些原子操作。

英特尔文档中给出的定义只允许使用 int、long、long long 以及它们的无符号对应类型。GCC 允许使用任何长度为 1、2、4 或 8 字节的积分标量或指针类型。

Note: 需要注意的是,随着C++11标准的引入,C++提供了更加高级和可移植的原子操作接口,如std::atomic。在新的代码中,建议使用这些标准库提供的原子操作接口,而不是依赖于特定编译器的内置函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 这些内置函数执行名称建议的操作,并返回先前在内存中的值。
# 将指针 ptr 指向的变量的值加上 value,并返回原来的值。
type __sync_fetch_and_add (type *ptr, type value, ...)

# 将指针 ptr 指向的变量的值减去 value,并返回原来的值。
type __sync_fetch_and_sub (type *ptr, type value, ...)

# 将指针 ptr 指向的变量的值按位或上 value,并返回原来的值。
type __sync_fetch_and_or (type *ptr, type value, ...)

# 将指针 ptr 指向的变量的值相与上 value,并返回原来的值。
type __sync_fetch_and_and (type *ptr, type value, ...)

# 将指针 ptr 指向的变量的值异或上 value,并返回原来的值。
type __sync_fetch_and_xor (type *ptr, type value, ...)

# 将指针 ptr 指向的变量的值取反后与 value值相与,并返回原来的值。
type __sync_fetch_and_nand (type *ptr, type value, ...)

# 这些内置函数执行名称建议的操作,并返回新值。
# 将指针 ptr 指向的变量的值加上 value 的值,并返回新的值。
type __sync_add_and_fetch (type *ptr, type value, ...)

# 将指针 ptr 指向的变量的值减去 value 的值,并返回新的值。
type __sync_sub_and_fetch (type *ptr, type value, ...)

# 将指针 ptr 指向的变量的值与 value 的值相或,并返回新的值。
type __sync_or_and_fetch (type *ptr, type value, ...)

# 将指针 ptr 指向的变量的值与 value 的值相与,并返回新的值。
type __sync_and_and_fetch (type *ptr, type value, ...)

# 将指针 ptr 指向的变量的值与 value 的值相异或,并返回新的值。
type __sync_xor_and_fetch (type *ptr, type value, ...)

# 将指针 ptr 指向的变量的值取反并与 value 的值相与,并返回新的值。
type __sync_nand_and_fetch (type *ptr, type value, ...)

# 这些内置函数执行原子比较和交换。
# 将指针 *ptr 指向的变量的值等于 oldval 值,则将newval写入*ptr,并且返回true
bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)

# 将指针 *ptr 指向的变量的值等于 oldval 值,则将newval写入*ptr,并且返回 *ptr 之前的值。
type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)

# 该内置函数产生完整的内存屏障。
__sync_synchronize (...)

# 将 value 值写入到指针 *ptr 变量中,并且返回操作之前的值。
type __sync_lock_test_and_set (type *ptr, type value, ...)

# 将0写入到 *ptr 变量中,并对其解锁。
void __sync_lock_release (type *ptr, ...)
# __sync_lock_release 是GCC内置的原子操作函数之一,用于释放一个锁。这个函数通常与 __sync_lock_test_and_set 配合使用,用于实现基本的自旋锁。自旋锁是一种同步机制,它会一直尝试获取锁,如果锁已经被占用,则一直忙等待(自旋)直到获取到锁为止。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#ifndef __ATOMIC_H__
#define __ATOMIC_H__

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* The atomic counter structure.
*/
typedef struct {
volatile int32_t cnt; /**< An internal counter value. */
} atomic32_t;

/**
* Atomically read a 32-bit value from a counter.
*
* @param v
* A pointer to the atomic counter.
* @return
* The value of the counter.
*/
static inline int32_t
atomic32_read(const atomic32_t *v)
{
return v->cnt;
}

/**
* Atomically set a counter to a 32-bit value.
*
* @param v
* A pointer to the atomic counter.
* @param new_value
* The new value for the counter.
*/
static inline void
atomic32_set(rte_atomic32_t *v, int32_t new_value)
{
v->cnt = new_value;
}

/**
* Atomically add a 32-bit value to an atomic counter.
*
* @param v
* A pointer to the atomic counter.
* @param inc
* The value to be added to the counter.
*/
static inline void
atomic32_add(atomic32_t *v, int32_t inc)
{
__sync_fetch_and_add(&v->cnt, inc);
}

/**
* Atomically subtract a 32-bit value from an atomic counter.
*
* @param v
* A pointer to the atomic counter.
* @param dec
* The value to be subtracted from the counter.
*/
static inline void
atomic32_sub(atomic32_t *v, int32_t dec)
{
__sync_fetch_and_sub(&v->cnt, dec);
}

/**
* Atomically add a 32-bit value to a counter and return the result.
*
* Atomically adds the 32-bits value (inc) to the atomic counter (v) and
* returns the value of v after addition.
*
* @param v
* A pointer to the atomic counter.
* @param inc
* The value to be added to the counter.
* @return
* The value of v after the addition.
*/
static inline int32_t
atomic32_add_return(atomic32_t *v, int32_t inc)
{
return __sync_add_and_fetch(&v->cnt, inc);
}

/**
* Atomically subtract a 32-bit value from a counter and return
* the result.
*
* Atomically subtracts the 32-bit value (inc) from the atomic counter
* (v) and returns the value of v after the subtraction.
*
* @param v
* A pointer to the atomic counter.
* @param dec
* The value to be subtracted from the counter.
* @return
* The value of v after the subtraction.
*/
static inline int32_t
atomic32_sub_return(atomic32_t *v, int32_t dec)
{
return __sync_sub_and_fetch(&v->cnt, dec);
}


static inline int atomic32_inc_and_test(atomic32_t *v)
{
return (__sync_add_and_fetch(&v->cnt, 1) == 0);
}

/**
* Atomically subtract a 32-bit value from a counter and return
* the result.
*
* Atomically subtracts the 32-bit value (inc) from the atomic counter
* (v) and returns the value of v after the subtraction.
*
* @param v
* A pointer to the atomic counter.
* @param dec
* The value to be subtracted from the counter.
* @return
* The value of v after the subtraction.
*/
static inline int32_t
atomic32_sub_return(atomic32_t *v, int32_t dec)
{
return __sync_sub_and_fetch(&v->cnt, dec);
}

#define atomic_t atomic32_t
#define atomic_read(v) atomic32_read(v)
#define atomic_set(v, i) rte_atomic32_set(v, i)

#define atomic_inc(v) rte_atomic32_add(v, 1)
#define atomic_dec(v) rte_atomic32_sub(v, 1)

#define atomic_inc_and_test(v) rte_atomic32_inc_and_test(v)
#define atomic_dec_and_test(v) rte_atomic32_dec_and_test(v)

#define atomic_inc_return(v) rte_atomic32_add_return(v, 1)
#define atomic_dec_return(v) rte_atomic32_sub_return(v, 1)
#define atomic_sub_and_test(i, v) (rte_atomic32_sub_return(v, i) == 0)

#ifdef __cplusplus
}
#endif /* __cpluscplus*/

#endif

reference

[1] https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/_005f_005fsync-Builtins.html#_005f_005fsync-Builtins

小主,路过打个赏再走呗~