学习笔记——操作系统_Linux原子操作

来源:互联网 发布:数据库管理系统的应用 编辑:程序博客网 时间:2024/05/01 19:32

这篇摘录有关原子操作的说明,参考了以下的文章,并添加我的说明

 http://blog.csdn.net/vividonly/article/details/6599502(针对原子操作解释的很全面)

http://baike.baidu.com/view/809659.htm

http://blog.csdn.net/sunupzhou/article/details/7537779

http://blog.sina.com.cn/s/blog_6472c4cc0100qxcd.html(这个哥们的技术很全面)


所谓原子操作,就是“不可中断的一个或一系列操作”。

硬件级的原子操作在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只发生在指令边缘。

【说明】这个单条指令中完成的操作,因为中断只能在指令边缘,可以这么理解:中断发生时,流水线会把当前中断之前的指令执行完,直至修改处理器状态,而中断发生之后的指令排空,并且中断之后的指令不能修改处理器状态,所以指令的状态修改都是在指令提交阶段完成。

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

【说明】在多处理器系统中,由于基于cache一致性协议原则,当系统修改内存中的某个值时,会告知其他所有当前cache该值的CPU;这儿也隐含说明:所谓的原子操作,是针对内存的操作,而不是针对寄存器的操作,这个时候要写穿透。

问题:我们已经通过cache一致性协议确保数据正确了,为什么还要通过上述机制进行原子操作呢?

分析cache一致性协议,主要是当前常用的基于目录的cache一致性协议:

cache中数据的状态包括:

  • 共享:一个或者多个处理器拥有cache的数据块
  • 未缓存:没有任何一个处理器含有该数据块
  • 修改:只有一个处理器拥有该cache块的副本并已经进行写操作
当在SMP中某个处理器修改了内存中的值之后,即cache数据状态变为修改,这个时候要传递到其他的处理器中,这个时候通过目录协议,是通过目录控制器有选择的发送数据获取和无效操作来完成的。任何cache块要执行写操作时都必须处于独占的状态,而且共享数据在存储器中的副本必须被替换。

在这个时候,当处理器A写数据后,系统应该通过目录控制器将处理器B中的值设定为无效。这个时候为什么还要额外处理呢?


软件层面的原子操作:

原子操作通常针对int或bit类型的数据,但是Linux并不能直接对int进行原子操作,而只能通过atomic_t的数据结构来进行。目前了解到的原因有两个。一是在老的Linux版本,atomic_t实际只有24位长,低8位用来做锁。这是由于Linux是一个跨平台的实现,可以运行在多种 CPU上,有些类型的CPU比如SPARC并没有原生的atomic指令支持,所以只能在32位int使用8位来做同步锁,避免多个线程同时访问。(最新版SPARC实现已经突破此限制)。原子整数操作最常见的用途就是实现计数器。常见的用法是:

atomic_t use_cnt;atomic_set(&use_cnt, 2);atomic_add(4, &use_cnt);atomic_inc(use_cnt);

系统中具体的实现方式就不管了。

为什么关注原子操作
1)在确认一个操作是原子的情况下,多线程环境里面,我们可以避免仅仅为保护这个操作在外围加上性能开销昂贵的锁。
2)借助于原子操作,我们可以实现互斥锁。
3)借助于互斥锁,我们可以把一些列操作变为原子操作

原创粉丝点击