Linux中同步互斥机制研究之原子操作
操作系统中,对共享资源的访问需要有同步互斥机制来保证其逻辑的正确性,而这一切的基础便是原子操作。
| 原子操作(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中同步互斥机制研究之原子操作的更多相关文章
- 【原创】xenomai内核解析--同步互斥机制(一)--优先级倒置
版权声明:本文为本文为博主原创文章,转载请注明出处.如有错误,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ 目录 一.xenomai 资源管理简要 二.优先级倒 ...
- 浅谈Linux中的信号处理机制(二)
首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...
- Linux中的保护机制
Linux中的保护机制 在编写漏洞利用代码的时候,需要特别注意目标进程是否开启了NX.PIE等机制,例如存在NX的话就不能直接执行栈上的数据,存在PIE 的话各个系统调用的地址就是随机化的. 一:ca ...
- LINUX中的RCU机制的分析
RCU机制是Linux2.6之后提供的一种数据一致性访问的机制,从RCU(read-copy-update)的名称上看,我们就能对他的实现机制有一个大概的了解,在修改数据的时候,首先需要读取数据,然后 ...
- linux中的阻塞机制及等待队列
阻塞与非阻塞是设备访问的两种方式.驱动程序需要提供阻塞(等待队列,中断)和非阻塞方式(轮询,异步通知)访问设备.在写阻塞与非阻塞的驱动程序时,经常用到等待队列. 一.阻塞与非阻塞 阻塞调用是没有获得资 ...
- linux中的阻塞机制及等待队列【转】
转自:http://www.cnblogs.com/gdk-0078/p/5172941.html 阻塞与非阻塞是设备访问的两种方式.驱动程序需要提供阻塞(等待队列,中断)和非阻塞方式(轮询,异步通知 ...
- Linux之同步互斥阻塞20160703
主要介绍一下Linux下的互斥与阻塞方面的知识: 1. 原子操作 原子操作指的是在执行过程中不会被别的代码路径所中断的操作. 常用原子操作函数举例: atomic_t v = ATOMIC_INIT( ...
- linux中的tasklet机制【转】
转自:http://blog.csdn.net/yasin_lee/article/details/12999099 转自: http://www.kerneltravel.net/?p=143 中断 ...
- 总结一下linux中的分段机制
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 这篇文章主要说一下linux对于分段机制的处理,虽然都说linux不使用分段机制,但是分段机制属于CPU的一个功 ...
随机推荐
- linux系统下信号具体解释2
信号是UNIX 系统所使用的进程通信方法中,最古老的一种.信号不但能从内核发往一个进程,也能从一个进程发往还有一个进程.比如,用户在后台启动了一个要运行较长时间的程序,假设想中断其运行,能够用kill ...
- Web 存储之localStorage
1.localStorage的浏览器支持情况 localStorage属于永久性存储,不移除永久存在:sessionStorage属于会话结束就消失. localStorage存储的大小在5M左右,不 ...
- Dual Dijkstra search for planning multiple paths
The dual Dijkstra search for planning multiple paths is performed by: (1) calculating a first shorte ...
- 【OC语法要闻速览】一、方法调用
调用方法 [object method]; [object methodWithInput:input]; output = [object methodWithOutput]; output = [ ...
- IT 达人
1. 手机与电脑多屏互动 [教程]华为多屏互动功能与PC win7的连接 要求手机和电脑必须在同一局域网内,且手机必须支持多屏互动功能. 操作步骤如下: PC 端: services.msc,启动下面 ...
- EasyUI学习之menu and button(菜单和按钮)
前言 今天下午的天气感觉格外的气闷,整个人有一种黏糊糊的感觉,格外的不舒服.加之立即要放假了了,感觉自己全然坐不住呢(节前综合症么).只是学习还是的继续的. 原定计划这篇文章本来应该是关于search ...
- DDD实战10 在项目中使用JWT的token
在使用过程中报过一个错误:The algorithm: 'HS256' requires the SecurityKey.KeySize to be greater than '128' bits 是 ...
- Leetcode 238 Product of Array Except Self 递推
给出一个数组 nums[i](i = 0,1,...,n-1) 输出数组output[i]满足 output[i] = nums[0] * num[1] * num[2] *..*num[i-1] ...
- WPF 3D Transparency Depth-Order Sorting
原文:WPF 3D Transparency Depth-Order Sorting Just a quick post here - When making WPF 3D apps, trans ...
- Domain adaptation:连接机器学习(Machine Learning)与迁移学习(Transfer Learning)
domain adaptation(域适配)是一个连接机器学习(machine learning)与迁移学习(transfer learning)的新领域.这一问题的提出在于从原始问题(对应一个 so ...