Gcc内置原子操作__sync_系列函数简述及例程

函数声明 

Gcc 4.1.2版本之后,对X86或X86_64支持内置原子操作。就是说,不需要引入第三方库(如pthread)的锁保护,即可对1、2、4、8字节的数值或指针类型,进行原子加/减/与/或/异或等操作。有了这套内置原子操作函数,写程序方便很多。老宋根据Gcc手册中《Using the GNU Compiler Collection (GCC)》章节内容,将__sync_系列17个函数声明整理简化如下:

  1. type __sync_fetch_and_add (type *ptr, type value, ...)
    // 将value加到*ptr上,结果更新到*ptr,并返回操作之前*ptr的值
  2. type __sync_fetch_and_sub (type *ptr, type value, ...)
    // 从*ptr减去value,结果更新到*ptr,并返回操作之前*ptr的值
  3. type __sync_fetch_and_or (type *ptr, type value, ...)
    // 将*ptr与value相或,结果更新到*ptr, 并返回操作之前*ptr的值
  4. type __sync_fetch_and_and (type *ptr, type value, ...)
    // 将*ptr与value相与,结果更新到*ptr,并返回操作之前*ptr的值
  5. type __sync_fetch_and_xor (type *ptr, type value, ...)
    // 将*ptr与value异或,结果更新到*ptr,并返回操作之前*ptr的值
  6. type __sync_fetch_and_nand (type *ptr, type value, ...)
    // 将*ptr取反后,与value相与,结果更新到*ptr,并返回操作之前*ptr的值
  7. type __sync_add_and_fetch (type *ptr, type value, ...)
    // 将value加到*ptr上,结果更新到*ptr,并返回操作之后新*ptr的值
  8. type __sync_sub_and_fetch (type *ptr, type value, ...)
    // 从*ptr减去value,结果更新到*ptr,并返回操作之后新*ptr的值
  9. type __sync_or_and_fetch (type *ptr, type value, ...)
    // 将*ptr与value相或, 结果更新到*ptr,并返回操作之后新*ptr的值
  10. type __sync_and_and_fetch (type *ptr, type value, ...)
    // 将*ptr与value相与,结果更新到*ptr,并返回操作之后新*ptr的值
  11. type __sync_xor_and_fetch (type *ptr, type value, ...)
    // 将*ptr与value异或,结果更新到*ptr,并返回操作之后新*ptr的值
  12. type __sync_nand_and_fetch (type *ptr, type value, ...)
    // 将*ptr取反后,与value相与,结果更新到*ptr,并返回操作之后新*ptr的值
  13. bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
    // 比较*ptr与oldval的值,如果两者相等,则将newval更新到*ptr并返回true
  14. type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)
    // 比较*ptr与oldval的值,如果两者相等,则将newval更新到*ptr并返回操作之前*ptr的值
  15. __sync_synchronize (...)
    // 发出完整内存栅栏
  16. type __sync_lock_test_and_set (type *ptr, type value, ...)
    // 将value写入*ptr,对*ptr加锁,并返回操作之前*ptr的值。即,try spinlock语义
  17. void __sync_lock_release (type *ptr, ...)
    // 将0写入到*ptr,并对*ptr解锁。即,unlock spinlock语义 

例程 

并编写了一个简单小例子,测试多个工作线程同时对同一个全局变量g_iSum进行加法操作时,使用__sync_fetch_and_add()原子操作进行原子加法,和不使用原子操作进行普通加法,观察它们运行结果的区别。每个工作线程加500万次,共10个工作线程,预期结果是5000万。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int g_iFlagAtom = 1;
#define WORK_SIZE 5000000
#define WORKER_COUNT 10
pthread_t g_tWorkerID[WORKER_COUNT];
int g_iSum = 0;

void * thr_worker(void *arg) {
   printf ("WORKER THREAD %08X STARTUP\n", (unsigned int)pthread_self());
   int i=0;
   for (i=0; i<WORK_SIZE; ++i) {
       if (g_iFlagAtom) {
           __sync_fetch_and_add(&g_iSum, 1);
       } else {
           g_iSum ++;
       }
   }
   return NULL;
}

void * thr_management (void *arg) {
   printf ("MANAGEMENT THREAD %08X STARTUP\n", (unsigned int)pthread_self());
   int i;
   for (i=0;i<WORKER_COUNT;++i) {
       pthread_join(g_tWorkerID[i], NULL);
   }
   printf ("ALL WORKER THREADS FINISHED.\n");
   return NULL;
}

int main(int argc, const char* argv[]) {
   pthread_t tManagementID;
   pthread_create (&tManagementID, NULL, thr_management, NULL);
   int i=0; 
   for (i=0;i<WORKER_COUNT;++i) {
       pthread_create(&g_tWorkerID[i], NULL, thr_worker, NULL);
   }
   printf ("CREATED %d WORKER THREADS\n", i);
   pthread_join(tManagementID, NULL);
   printf ("THE SUM: %d\n", g_iSum);
   return 0;
}

不使用原子操作 

将g_iFlagAtom = 0,即不使用原子操作,可以看到输出结果无法达到预期的50000000,而且每次执行都可能得到不同的值。

gcc -std=gnu99 -g -Wall -o test.elf test.c
./test.elf

 使用原子操作 

将g_iFlagAtom = 1,即使用原子操作,可以看到输出结果为预期的50000000,而且每次执行都得到这个值不变。

gcc -std=gnu99 -g -Wall -o test.elf test.c
./test.elf

 

 =================================================================

此函数因该与VS中的 InterlockedCompareExchange 系列函数类似,待验证

未完待续。。。

 参考:

        https://zhuanlan.zhihu.com/p/32303037

 Reference:

0. 老宋的独家号 ( http://songke.online )

1. Using the GNU Compiler Collection (GCC)

 

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值