操作系统中,对共享资源的访问需要有同步互斥机制来保证其逻辑的正确性,而这一切的基础便是原子操作。

| 原子操作(Atomic Operations):

    原子操作从定义上理解,应当是类似原子的,不可再分的操作;然而实际上稍有不同,较为准确的定义应当是:不可被打断的一个或一系列操作。

  在单处理器系统中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只发生在指令边缘。在多处理器结构中就不同了,由于系统中有多个处理器独立运行,即使能在单条指令中完成的操作也有可能受到干扰。在X86平台上,CPU提供了在指令执行期间对总线加锁的手段。CPU上有一根引线#HLOCK pin连到北桥芯片,如果在汇编程序的指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,直到这条指令执行结束时才放开,从而将总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中对内存访问的原子性。

| 1. 为什么需要原子操作 

  我们来看一个例子,假设我们用两个线程,完成对全局变量 index 的自增至10的功能,我们这样写线程函数:

  

  执行结果如下,可以看到执行了两次,但结果却不一样(不是想象的值为10),事实上每次执行的结果都可能不一样。理论上,两个线程分别同时执行5次自增操作,只要执行正确应该总是得到10的结果,但是可以看到两个线程虽然可以交叉执行,index的值却不是从1增长到10。图中mthread程序第一次执行时,线程一将index增加到5后,线程二居然得到了2的结果,这是怎么回事?

  

  我们知道,在计算机中,变量的值是存储在内存中的,要知道一个存储在内存中的变量的值就需要读内存,需要更新这个变量的值就必须写回去。如果这整个操作是不可打断的,那么是不会出现上面的结果的,所以中间肯定是出现了什么问题。事实上i++这种操作确实不是原子的,程序编译成汇编代码后就可以看到,i++实际上是由Read(读)-Modify(改)-Write(写) 3个操作实现的:

  

  

  如上图所示,两个线程分别在两个处理器核上执行,假设i的值刚开始是0,线程1先读取i的值,放到ax寄存器中,此时线程2也读取i的值,接着add eax,1,然后回写到i的地址中,此时i的值为1;之后线程1中再执行add eax,1,再回写到i的地址,所以i的值就是1,而不是2。如果需要将i++变成原子的就需要一些额外的方式。

| 2. Linux中原子操作的实现 

  有了上述的感官认识,现在来说实现就顺理成章了。Linux中对原子操作的实现主要在 linux-2.6.28\arch\x86\include\asm 目录下的 Atomic_32.h 中,包括了一系列内联函数(因为这些函数的代码都不长,基本都采用内嵌汇编代码编写)。首先来看原子类型的数据结构 atomic_t的定义:

1 /*
2 * Make sure gcc doesn't try to be clever and move things around
3 * on us. We need to use _exactly_ the address the user gave us,
4 * not some alias that contains the same information.
5 */
6 typedef struct {
7 int counter;
8 } atomic_t;

  接着来看如何实现原子操作:

 1 /**
2 * atomic_add - add integer to atomic variable
3 * @i: integer value to add
4 * @v: pointer of type atomic_t
5 *
6 * Atomically adds @i to @v.
7 */
8 static inline void atomic_add(int i, atomic_t *v)
9 {
10 asm volatile(LOCK_PREFIX "addl %1,%0"
11 : "+m" (v->counter)
12 : "ir" (i));
13 }

  上面这段代码截自Atomic_32.h,即原子的加操作。这个函数的实现采用了内嵌汇编的方式,首先声明LOCK前缀(实际上是一个宏定义),以原子的方式执行指令addl  %1,%0,表示将输入操作数和输出操作数编号,将输入和输出相加后输出。其中“+m”中加号表示输出是可读可写的,括号内注明了是原子变量v->counter;m表示输出存储在内存之中。“ir”中 i 表示输入是一个直接操作数,r表示这里输入 i 是存储在寄存器中的。

  原子的加有了,原子的减自然也不难:

 1 /**
2 * atomic_sub - subtract integer from atomic variable
3 * @i: integer value to subtract
4 * @v: pointer of type atomic_t
5 *
6 * Atomically subtracts @i from @v.
7 */
8 static inline void atomic_sub(int i, atomic_t *v)
9 {
10 asm volatile(LOCK_PREFIX "subl %1,%0"
11 : "+m" (v->counter)
12 : "ir" (i));
13 }

  其他的原子操作就不举例了,总之原理就是这样,在有竞争的访问中,有时需要保证操作最后执行的逻辑正确性,就必须将某些操作或者指令设置为原子的。原子操作是其他的一些同步互斥机制的基础,有了原子操作就可以实现多核系统中其他的同步互斥机制了。

  参考文献:

[1].http://edsionte.com/techblog/archives/1809

[2].http://blog.csdn.net/qb_2008/article/details/6840808

Linux中同步互斥机制研究之原子操作的更多相关文章

  1. 【原创】xenomai内核解析--同步互斥机制(一)--优先级倒置

    版权声明:本文为本文为博主原创文章,转载请注明出处.如有错误,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ 目录 一.xenomai 资源管理简要 二.优先级倒 ...

  2. 浅谈Linux中的信号处理机制(二)

    首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...

  3. Linux中的保护机制

    Linux中的保护机制 在编写漏洞利用代码的时候,需要特别注意目标进程是否开启了NX.PIE等机制,例如存在NX的话就不能直接执行栈上的数据,存在PIE 的话各个系统调用的地址就是随机化的. 一:ca ...

  4. LINUX中的RCU机制的分析

    RCU机制是Linux2.6之后提供的一种数据一致性访问的机制,从RCU(read-copy-update)的名称上看,我们就能对他的实现机制有一个大概的了解,在修改数据的时候,首先需要读取数据,然后 ...

  5. linux中的阻塞机制及等待队列

    阻塞与非阻塞是设备访问的两种方式.驱动程序需要提供阻塞(等待队列,中断)和非阻塞方式(轮询,异步通知)访问设备.在写阻塞与非阻塞的驱动程序时,经常用到等待队列. 一.阻塞与非阻塞 阻塞调用是没有获得资 ...

  6. linux中的阻塞机制及等待队列【转】

    转自:http://www.cnblogs.com/gdk-0078/p/5172941.html 阻塞与非阻塞是设备访问的两种方式.驱动程序需要提供阻塞(等待队列,中断)和非阻塞方式(轮询,异步通知 ...

  7. Linux之同步互斥阻塞20160703

    主要介绍一下Linux下的互斥与阻塞方面的知识: 1. 原子操作 原子操作指的是在执行过程中不会被别的代码路径所中断的操作. 常用原子操作函数举例: atomic_t v = ATOMIC_INIT( ...

  8. linux中的tasklet机制【转】

    转自:http://blog.csdn.net/yasin_lee/article/details/12999099 转自: http://www.kerneltravel.net/?p=143 中断 ...

  9. 总结一下linux中的分段机制

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 这篇文章主要说一下linux对于分段机制的处理,虽然都说linux不使用分段机制,但是分段机制属于CPU的一个功 ...

随机推荐

  1. Winsock出错引起的断网

    背景 实验室有二十来台 PC 机,30+的服务器集群,网络拓扑比较复杂.简单地说,有网关连着校网,校网无法直接访问学校外的网络,只能通过拨 vpn 来实现外网访问.而校网最近也不稳定,时常断网. 今天 ...

  2. 为 Mac Finder 增加右键文件打包压缩(免费)

    在 Windows 上用惯了 7-Zip 和 WinRAR,来到 Mac 却突然发现没有类似的工具?Mac 自带的 Zip 工具确实让人吐糟无力,压缩率低就不说了,因为 Mac 上文件名是 Unico ...

  3. prism behavior图示

    原文:prism behavior图示 怕以后丢失,还是发一下,看起来可能会比较乱

  4. WPF 中的三维文字[转贴]

    原文:WPF 中的三维文字[转贴] 原文: http://msdn.microsoft.com/msdnmag/issues/07/10/Foundations/default.aspx?loc=zh ...

  5. Leetcode dfs Combination Sum

    Combination Sum Total Accepted: 17319 Total Submissions: 65259My Submissions Given a set of candidat ...

  6. #747 –在WPF程序的触摸操作中使用惯性移动 (Implementing Inertia during Touch Manipulation)

    原文:#747 –在WPF程序的触摸操作中使用惯性移动 (Implementing Inertia during Touch Manipulation) 原文地址:https://wpf.2000th ...

  7. 张汝京:CIDM模式进可攻、退可守,建议尝试

    飞象网讯(路金娣/文)大约30多年前一些美国.日本和欧洲的IDM半导体工厂把多余的产能出来做代工服务,因为代工的公司不会与客户竞争,所以专业代工的模式成为半导体市场的新宠.那么,究竟国内半导体行业更加 ...

  8. WPF Path实现虚线流动效果

    原文:WPF Path实现虚线流动效果 最近闲来无事,每天上上网,看看博客生活也过得惬意,这下老总看不过去了,给我一个任务,叫我用WPF实现虚线流动效果,我想想,不就是虚线流动嘛,这简单于是就答应下来 ...

  9. XF 列表视图事件

    <?xml version="1.0" encoding="utf-8" ?><ContentPage xmlns="http:// ...

  10. 2017 JavaScript 开发者的学习图谱

    码云项目推荐 前端框架类 1.项目名称: 基于 Vue.js 的 UI 组件库 iView 项目简介:iView 是一套基于 Vue.js 的 UI 组件库,主要服务于 PC 界面的中后台产品. 特性 ...