原子操作提供了指令原子执行,中间没有中断。就像原子被认为是不可分割颗粒一样,原子操作(atomic operation)是不可分割的操作。

如下面简单的例子:

Thread 1                  Thread 2
---------------------------------------------
get i (7)                 get i (7)

increment i (7->8)

---                      increment i (7->8)

write back i (8)          ----

---                          write back i (8)

如果有原子操作的话,那么这种竞争就不会发生,也不可能发生,结果只能是下面的一种:

Thread 1                            Thread 2
--------------------------------------------------------
get, increment, and store i(7->8)        ---

---                                 get, increment, and store i(8->9)

或者

Thread 1                            Thread 2
--------------------------------------------------------
---                                  get, increment, and store i(7->8)        
get, increment, and store i(8->9)          ---

在linux下,原子整数操作方法是一个特殊的类型,atomic_t,原型定义如下:

typedef struct{

    volatile int counter;

} atomic_t;

对于声明为volatile的好处,可以参考【百度百科-volatile】:http://baike.baidu.com/view/608706.htm?fr=aladdin

定义一种这样的类型有两种好处:1、让那些原子操作函数只接受atomic_t的数据类型作为参数,同样的也确保了这种数据类型不会传到其他的非原子操作函数;2、通过使用atomic_t这种数据类型是gcc编译器不会对这种类型的值的存取进行优化,因为对于原子操作收到正确的内存地址是非常重要的,确保不是别名。

在linux内核源码中对于原子操作的数据类型和方法描述文件为arch/x86/include/asm/atomic.h(注:这是对于内核为2.6.39以及处理器为x86的,其他的可能在不同的目录下)。一些体系结构提供了独特的原子操作方法。

下面介绍几种原子操作方法:

/**
 * atomic_add - add integer to atomic variable
 * @i: integer value to add
 * @v: pointer of type atomic_t
 *
 * Atomically adds @i to @v.
 */
static inline void atomic_add(int i, atomic_t *v)
{
    asm volatile(LOCK_PREFIX "addl %1,%0"
             : "+m" (v->counter)
             : "ir" (i));
}
上面的是对于原子加操作。采用的方式是先对内存进行加锁,是其他的CPU不能存取内存。

关于内联汇编的方式【基本知识】:http://www.cppblog.com/jb8164/archive/2008/02/26/43260.html;

如果想要内联汇编【深入理解】:http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html;

/**
 * atomic_sub - subtract integer from atomic variable
 * @i: integer value to subtract
 * @v: pointer of type atomic_t
 *
 * Atomically subtracts @i from @v.
 */
static inline void atomic_sub(int i, atomic_t *v)
{
    asm volatile(LOCK_PREFIX "subl %1,%0"
             : "+m" (v->counter)
             : "ir" (i));
}

进行的原子减操作采用的是类似的方式;也是先对内存加锁,然后再操作。

/**
 * atomic_read - read atomic variable
 * @v: pointer of type atomic_t
 *
 * Atomically reads the value of @v.
 */
static inline int atomic_read(const atomic_t *v)
{
    return (*(volatile int *)&(v)->counter);
}

这个是对于原子的读操作。为了防止编译器对数值进行优化而采用的是寄存器中的数值,需要将其转换为volatile类型的数据,使之每次都从内存中读取,对于每次读取操作不会发生读到一半的情况,每次读操作要么才写操作之前,要么在写操作之后。

其他的原子操作采用的是类似的方式。

最新文章

  1. 【无私分享:ASP.NET CORE 项目实战(第六章)】读取配置文件(一) appsettings.json
  2. 【USACO 2.4】The Tamworth Two
  3. Html5知识
  4. 2016.04.09 使用Powerdesigner进行创建数据库的概念模型并转为物理模型
  5. Orchard helloworld
  6. HDU 3006 The Number of set(位运算 状态压缩)
  7. 线程取消 (pthread_cancel)
  8. poj2583---Series Determination
  9. 驱动05.lcd设备驱动程序
  10. mongoDB2--mongoDB的下载和安装。
  11. ASP.NET Core MVC 源码学习:MVC 启动流程详解
  12. c#编写一个简单的http服务器
  13. href=#与href=javascript:void(0)的区别
  14. 使用StringEscapeUtils对Java中特殊字符进行转义和反转义
  15. Android studio button 按钮 四种绑定事件的方法
  16. 记一个js中的map数据结构
  17. mysql 导出sql结果成csv文件
  18. 用Swift实现一款天气预报APP(二)
  19. 【bzoj2115】[Wc2011] Xor
  20. python3----字符串格式化(format)

热门文章

  1. 【代码笔记】iOS-长条蓝色button
  2. javascript获取网页各种高宽及位置总结
  3. Gson解析复杂JSON字符串的两种方式
  4. AJAX四种跨域处理方法
  5. LeetCode题解之Univalued Binary Tree
  6. Prometheus Node_exporter 之 Network Netstat TCP Linux MIPs
  7. 学习笔记:Analyze MySQL Performance及慢日志的开启
  8. Configure network bonding on RHEL (Red Hat Enterprise Linux)
  9. python设计模式之门面模式
  10. python-异常处理try_except