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

Gcc 4.1.2版本之后,对X86或X86_64支持内置原子操作。就是说,不需要引入第三方库(如pthread)的锁保护,即可对1、2、4、8字节的数值或指针类型,进行原子加/减/与/或/异或等操作。

  1. __sync_fetch_and_add系列一共有十二个函数,有加/减/与/或/异或/等函数的原子性操作函
  1. __snyc_fetch_and_add : fetch然后自加,返回的是自加以前的值
  2. __snyc_add_and_fetch : 先自加然后返回,返回的是自加以后的值 (参照 ++i i++)
  3. __snyc_fetch_and_add的一个简单使用:
  4. int count = 4;
  5. __sync_fetch_and_add(&count, 1); // __sync_fetch_and_add(&count, 1) == 4
  6. cout<<count<<endl; //--->count=5

2.对于多线程对全局变量进行自加,我们就再也不用理线程锁了。

下面这行代码,和上面被pthread_mutex保护的那行代码作用是一样的,而且也是线程安全的。

  1. __sync_fetch_and_add( &global_int, 1 );

将__sync_系列17个函数声明整理简化如下:

  1. type __sync_fetch_and_add (type *ptr, type value, ...);
  2. type __sync_fetch_and_sub (type *ptr, type value, ...);
  3. type __sync_fetch_and_or (type *ptr, type value, ...);
  4. type __sync_fetch_and_and (type *ptr, type value, ...);
  5. type __sync_fetch_and_xor (type *ptr, type value, ...);
  6. type __sync_fetch_and_nand (type *ptr, type value, ...);
  7. type __sync_add_and_fetch (type *ptr, type value, ...);
  8. type __sync_sub_and_fetch (type *ptr, type value, ...);
  9. type __sync_or_and_fetch (type *ptr, type value, ...);
  10. type __sync_and_and_fetch (type *ptr, type value, ...);
  11. type __sync_xor_and_fetch (type *ptr, type value, ...);
  12. type __sync_nand_and_fetch (type *ptr, type value, ...);

__sync_fetch_and_add,速度是线程锁的6~7倍

type可以是1,2,4或者8字节长度的int类型,即:

  1. int8_t
  2. uint8_t
  3. int16_t
  4. uint16_t
  5. int32_t
  6. uint32_t
  7. int64_t
  8. uint64_t

3.例程

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

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. int g_iFlagAtom = 1;
  5. #define WORK_SIZE 5000000
  6. #define WORKER_COUNT 10
  7. pthread_t g_tWorkId[WORKER_COUNT];
  8. int g_iSum;
  9. void* thr_work(void *arg)
  10. {
  11. printf("Work Thread %08X Startup\n", (unsigned int)pthread_self());
  12. int i;
  13. for(i = 0; i < WORK_SIZE; i++)
  14. {
  15. if(g_iFlagAtom)
  16. __sync_fetch_and_add(&g_iSum, 1);
  17. else
  18. g_iSum++;
  19. }
  20. return NULL;
  21. }
  22. void* thr_management(void *arg)
  23. {
  24. printf("Management Thread %08X Startup\n", (unsigned int)pthread_self());
  25. int i;
  26. for(i = 0; i < WORKER_COUNT; i++)
  27. {
  28. pthread_join(g_tWorkId[i], NULL);
  29. }
  30. printf("All Work Thread Finished!\n");
  31. return NULL;
  32. }
  33. int main(int argc, const char* argv[])
  34. {
  35. pthread_t tManagementId;
  36. pthread_create(&tManagementId, NULL, thr_management, NULL);
  37. int i;
  38. for(i = 0; i < WORKER_COUNT; i++)
  39. {
  40. pthread_create(&g_tWorkId[i], NULL, thr_work, NULL);
  41. }
  42. printf("create %d worker threads\n", i);
  43. pthread_join(tManagementId, NULL);
  44. printf("the sum:%d\n", g_iSum);
  45. return 0;
  46. }

不使用原子操作

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

  1. gcc -Wall -o atom atom.cc -l pthread
  2. ./atom

使用原子操作

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

  1. gcc -Wall -o atom1 atom.cc -l pthread
  2. ./atom1

Gcc内置原子操作__sync_系列函数的更多相关文章

  1. GCC内置函数

    在C语言写的程序中,有时候没有包含头文件,直接调用一些函数,如printf,也不会报错,因为GCC内置和一些函数.如果包含了头文件,则去第三方库中链接这个函数,不再使用GCC内置的函数.每个编译器的内 ...

  2. gcc 内置函数

    关于gcc内置函数和c隐式函数声明的认识以及一些推测   最近在看APUE,不愧是经典,看一点就收获一点.但是感觉有些东西还是没说清楚,需要自己动手验证一下,结果发现需要用gcc,就了解一下. 有时候 ...

  3. Python内置的字符串处理函数整理

    Python内置的字符串处理函数整理 作者: 字体:[增加 减小] 类型:转载 时间:2013-01-29我要评论 Python内置的字符串处理函数整理,收集常用的Python 内置的各种字符串处理 ...

  4. 原子操作 Interlocked系列函数

    上一篇<多线程第一次亲密接触 CreateThread与_beginthreadex本质区别>中讲到一个多线程报数功能.为了描述方便和代码简洁起见,我们可以只输出最后的报数结果来观察程序是 ...

  5. PHP内置的字符串处理函数

    字符串的特点    1.其他类型的数据用在字符串类型处理函数中,会自动将其转化成字符串后,在处理 <?php echo substr("abcdefghijklmn",2,4 ...

  6. (转)原子操作 Interlocked系列函数

    上一篇<多线程第一次亲密接触 CreateThread与_beginthreadex本质区别>中讲到一个多线程报数功能.为了描述方便和代码简洁起见,我们可以只输出最后的报数结果来观察程序是 ...

  7. 多线程面试题系列(3):原子操作 Interlocked系列函数

    上一篇中讲到一个多线程报数功能.为了描述方便和代码简洁起见,我们可以只输出最后的报数结果来观察程序是否运行出错.这也非常类似于统计一个网站每天有多少用户登录,每个用户登录用一个线程模拟,线程运行时会将 ...

  8. thinkPHP内置字符串截取msubstr函数用法详解

    作者:陈达辉 字体:[增加 减小] 类型:转载 时间:2016-11-15 我要评论 这篇文章主要介绍了thinkPHP内置字符串截取函数用法,结合实例形式分析了thinkPHP内置的字符串截取函数功 ...

  9. 秒杀多线程第三篇 原子操作 Interlocked系列函数

    上一篇<多线程第一次亲密接触 CreateThread与_beginthreadex本质区别>中讲到一个多线程报数功能.为了描述方便和代码简洁起见,我们可以只输出最后的报数结果来观察程序是 ...

  10. python内置常用高阶函数(列出了5个常用的)

    原文使用的是python2,现修改为python3,全部都实际输出过,可以运行. 引用自:http://www.cnblogs.com/duyaya/p/8562898.html https://bl ...

随机推荐

  1. (Good topic)卡牌分组(3.27leetcode每日打卡)

    给定一副牌,每张牌上都写着一个整数. 此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组:  每组都有 X 张牌. 组内所有的牌上都写着相同的整数. 仅当你可选的 X &g ...

  2. Java 删除PDF页面 (免费工具分享)

    对PDF页面的增删通常需要借助专门的工具,而这些工具一般需要付费才能使用.那么我们可以通过Java代码免费实现这一功能吗?答案是肯定的.这篇文章就教大家如何使用一个免费的国产Java库来删除PDF中的 ...

  3. 【Javaweb】关于html转成jsp时出现乱码的问题解决

    原因是没有在代码头部添加,下面这段代码,添加之后就解决了 <%@ page language="java" contentType="text/html; char ...

  4. 一次elasticsearch 查询瞬间超时案例分析

    大家好,我是蓝胖子,有段时间没有做性能分析案例讲解了,正好前两天碰到一个性能问题,今天就来对它探讨探讨. 问题背景 在晚上9点左右,刚从外面逛街回到家,就接到了电话报警(幸好前不久刚好把电话报警机制加 ...

  5. 使用CompletableFuture实现多个异步任务并行完成后合并结果

    业务场景 需要同时从多个副本数据库中查询数据,并对查询结果进行合并去重处理后返回前端. 实现过程涉及多数据源切换,这里不作过多讨论. 编码实现 实现过程: 1.定义异步查询数据方法: 2.通过Comp ...

  6. Reactor实战,创建一个简单的单线程Reactor(理解了就相当于理解了多线程的Reactor)

    单线程Reactor package org.example.utils.echo.single; import java.io.IOException; import java.net.InetSo ...

  7. [NOI online22提高A] 丹钓战

    题目描述 有 \(n\) 个二元组 \((a_i, b_i)\),编号为 1 到 n. 有一个初始为空的栈 SS,向其中加入元素 \((a_i, b_i)\) 时,先不断弹出栈顶元素直至栈空或栈顶元素 ...

  8. [GDOI22pj2D] 机器人

    第四题 机器人 提交文件: robot.cpp 输入文件: robot.in 输出文件: robot.out 时间空间限制: 3 秒, 512 MB 刚上初一的小纯特别喜欢机器人,这周末,她报名了学校 ...

  9. Head First Java学习:第十章-数字很重要

     1.Math 方法:最接近全局的方法 一种方法的行为不依靠实例变量值,方法对参数执行操作,但是操作不受实例变量状态影响,那么为了执行该方法去堆上建立对象实例比较浪费. 举例: Math mathOb ...

  10. 基于winform(C#)的飞鸟小游戏

    本项目是一款基于C# (winform)版本的飞鸟小游戏,是一款益智类游戏 其效果如下图所示 如上图所示为飞鸟游戏的初始化界面: 可以看到游戏包含了四个功能: 启动 注册 登陆 排行榜 启动:是用于开 ...