gcc 里提供了内置 CAS 函数:__atomic_compare_exchange_n(),它的基本用法如下:
Built-in Function: bool __atomic_compare_exchange_n (type *ptr, type *expected, type desired, bool weak, int success_memorder, int failure_memorder)
This built-in function implements an atomic compare and exchange operation. This compares the contents of
*ptr
with the contents of*expected
. If equal, the operation is a read-modify-write operation that writes desired into*ptr
. If they are not equal, the operation is a read and the current contents of*ptr
are written into*expected
. weak istrue
for weak compare_exchange, which may fail spuriously, andfalse
for the strong variation, which never fails spuriously. Many targets only offer the strong variation and ignore the parameter. When in doubt, use the strong variation.If desired is written into
*ptr
thentrue
is returned and memory is affected according to the memory order specified by success_memorder. There are no restrictions on what memory order can be used here.Otherwise,
false
is returned and memory is affected according to failure_memorder. This memory order cannot be__ATOMIC_RELEASE
nor__ATOMIC_ACQ_REL
. It also cannot be a stronger order than that specified by success_memorder.
在使用中,可以用它来实现 spinlock,具体代码如下:
#include <stdio.h>
#include <stdbool.h>
#include <pthread.h>
#define THREAD_NUM 32
volatile unsigned int sum = 0;
unsigned int max = 10000000;
volatile bool cond = true;
typedef int slock_t;
static __inline__ int
cas(volatile slock_t *lock)
{
slock_t expected = 0;
return !(__atomic_compare_exchange_n(lock, &expected, (slock_t)1,
false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE));
}
#define S_UNLOCK(lock) __atomic_store_n(lock, (slock_t)0, __ATOMIC_RELEASE)
#define S_INIT_LOCK(lock) S_UNLOCK(lock)
#define SPIN(lock) (*(lock) ? 1 : cas(lock))
volatile slock_t g_lock;
int s_lock(volatile slock_t *lock)
{
int i = 0;
while (SPIN(lock))
{
++i;
}
return i;
}
void *thread_func(void *args)
{
while ((cond = sum < max)) {
s_lock(&g_lock);
++sum;
S_UNLOCK(&g_lock);
}
return NULL;
}
int main(void)
{
pthread_t pids[THREAD_NUM];
int i, ret;
void *val;
double start, end;
S_INIT_LOCK(&g_lock);
for (i = 0; i < THREAD_NUM; ++i) {
ret = pthread_create(&pids[i], NULL, thread_func, NULL);
}
for (i = 0; i < THREAD_NUM; ++i) {
pthread_join(pids[i], &val);
}
printf("final sum: %d\n", sum);
return 0;
}
运行结果如下:
$ ./main
final sum: 10000031
参考资料
1. https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html