《单核,多核CPU的原子操作.pdf》由会员分享,可在线阅读,更多相关《单核,多核CPU的原子操作.pdf(7页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、单核,多核 CPU的原子操作 一.何谓 原子操作:原子操作就是:不可中断的一个或者一系列操作,也就是不会被线程调度机制打断的操作,运行期间不会有任何的上下文切换(context switch).二.为什么关注原子操作?1.如果确定某个操作是原子的,就不用为了去保护这个操作而加上会耗费昂贵性能开销的锁.-(巧妙的利用原子操作和实现无锁编程)2.借助原子操作可以实现互斥锁(mutex).(linux中的 mutex_lock_t)3.借助互斥锁,可以实现让更多的操作变成原子操作.三.单核 CPU的原子操作:在单核 CPU中,能够在一个指令中完成的操作都可以看作为原子操作,因为中断只发生在指令间.四
2、.多核 CPU的原子操作:在多核 CPU的时代(确实 moore定律有些过时了,我们需要更多的 CPU,而不是更快的 CPU,无法处理快速 CPU中的热量散发问题),体系中运行着多个独立的 CPU,即使是可以在单个指令中完成的操作也可能会被干扰.典型的例子就是 decl指令(递减指令),它细分为三个过程:读-改-写,涉及两次内存操作.如果多个 CPU运行的多个进程在同时对同一块内存执行这个指令,那情况是无法预测的.五.硬件支持&多核原子操作:软件级别的原子操作是依赖于硬件支持的.在 x86体系中,CPU提供了HLOCK pin引线,允许CPU在执行某一个指令(仅仅是一个指令)时拉低 HLOCK
3、 pin引线的电位,直到这个指令执行完毕才放开.从而锁住了总线,如此在同一总线的 CPU就暂时无法通过总线访问内存了,这样就保证了多核处理器的原子性.(想想这机制对性能影响挺大的).六.哪些操作可以确定为原子操作了?对于非 long和 double基本数据类型的 简单操作 都可以看作是原子的.例如:赋值和返回.大多数体系中 long和 double都占据8 个字节,操作系统或者 JVM很可能会将写入和读取操作分离为两个单独的 32 位的操作来执行,这就产生了在一个读取和写入过程中一个上下文切换(context switch),从而导致了不同任务线程看到不正确结果的的可能性.递增,递减不是原子操
4、作:i+反汇编的汇编指令:(需要三条指令操作,和两个内存访问,一次寄存器修改)1 2 3 movl i,%eax /内存访问,读取 i 变量的值到cpu的 eax寄存器 addl$1,%eax /增加寄存器中的值 movl%eax,i /写入寄存器中的值到内存 七.如何实现+i和 i+的原子性:1.单 CPU,使用锁或则禁止多线程调度,因为本身单核 CPU的并发就是伪并发.(在单核 CPU中,在没有阻塞的程序中使用多线程是没必要的).2.多核 CPU,就需要借助上面说道的 CPU提供的 Lock,锁住总线.防止在 读取,修改,写入 整个过程期间其他 CPU 访问内存.(那么“读写,修改,写入”
5、这个操作会不会在在单核中发生线程的切换呢?)八.Linux提供的两个原子操作接口:1.原子整数操作 针对整数的原子操作只能对 atomic_t类型的数据处理。这里没有使用 C 语言的 int类型,主要是因为:1)让原子函数只接受 atomic_t类型操作数,可以确保原子操作只与这种特殊类型数据一起使用.2)使用 atomic_t类型确保编译器不对相应的值进行访问优化.(原理为:变量被 volatile修饰了)3)使用 atomic_t类型可以屏蔽不同体系结构上的数据类型的差异。尽管 Linux支持的所有机器上的整型数据都是 32位,但是使用 atomic_t的代码只能将该类型的数据当作 24位
6、来使用。这个限制完全是因为在 SPARC体系结构上,原子操作的实现不同于其它体系结构:32 位 int类型的低 8 位嵌入了一个锁,因为 SPARC体系结构对原子操作缺乏指令级的支持,所以只能利用该锁来避免对原子类型数据的并发访问。原子整数操作最常见的用途就是实现计数器。原子整数操作列表在中定义。原子操作通常是内敛函数,往往通过内嵌汇编指令来实现。如果某个函数本来就是原子的,那么它往往会被定义成一个宏。在编写内核时,操作 demo如下:1 2 3 4 atomic_t cnt;atomic_set(&cnt,2);atomic_add(4,&cnt);atomic_inc(cnt);2.原子位
7、操作:原子位操作定义在文件中。令人感到奇怪的是位操作函数是对普通的内存地址进行操作的。原子位操作在多数情况下是对一个字节长的内存(注 1)访问,因而位号该位于 0-31之间(在 64 位机器上是 0-63之间),但是对位号的范围没有限制。注 1:操作系统可以确保,在同一时刻,只有一个 CPU的一个进程访问特定的某个字节,再加上单核中的原子性(基本数据类型的简单操作),所以单字节内存的简单操作是具有天生的多核原子性的。编写内核代码,把要操作的数据的指针给操作函数,就可以进行位操作了:1 2 3 4 5 unsigned long var=0;set_bit(0,&var);/*set the 0
8、th bit*/set_bit(1,&var);/*set the 1th bit*/clear_bit(1,&var);/*clear the 1th bit*/change_bit(0,&var);/*change the 1th bit*/九.spinlock CPU同步:spin lock必须基于CPU的数据总线锁定,它通过读取一个内存单元(spinlock_t)来判断这个 spinlock是否已经被别的 CPU锁住.如果否,它写进一个特定值,表示锁定了总线,然后返回.如果是,它会重复以上操作直到成功,或者 spin 次数超过一个设定值.记住上面提及到的:锁定数据总线的指令只能保证一个指令操作期间 CPU独占数据总线.(spinlock在锁定的时侯,不会睡眠而是会持续的尝试).