原子操作及对C++编程的意义

来源:互联网 发布:php培训机构达内教育 编辑:程序博客网 时间:2024/04/25 06:53

前言     

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

      在单核心处理器系统中,能够在一条机器指令中完成的操作都可以认为是原子操作,因为中断只能发生于指令之间。这也是某些CPU指令系统中引入了test_and_set、test_and_clear等指令用于临界资源互斥的原因。
在对称多处理器(Symmetric Multi-Processor)结构中就不同了,由于系统中有多个处理器在独立地运行,即使能在单条指令中完成的操作也有可能受到干扰。

CPU对原子操作的影响

intel处理器

      《Intel 64 and IA-32 Architectures Software Developer`s Manual》Volume3 System Programming Guide,8.1.1 Guaranteed Atomic Operations中讲解的原子操作如下:

      Intel486处理器(以及以后生产的处理器)确保以下对基本存储器的操作行为为原子操作:
      Reading or writing a byte
      读写一个byte
      Reading or writing a word aligned on a 16-bit boundary
      读写16bit(2byte)内存对齐的字(word)
      Reading or writing a doubleword aligned on a 32-bit boundary
      读写32bit(4byte)内存对齐的双字(dword)
      The Pentium processor (and newer processors since) guarantees that the following additional memory operationswill always be carried out atomically:
      Pentium系列处理器(以及以后生产的处理器)确保以下对基本存储器的操作行为为原子操作:
      Reading or writing a quadword aligned on a 64-bit boundary
      读写64bit(8byte)内存对齐的四字(quadword)
      16-bit accesses to uncached memory locations that fit within a 32-bit data bus
      使用16bit访问的未缓存的内存,并且这些内存适应32位数据总线(翻译不好)
      The P6 family processors (and newer processors since) guarantee that the following additional memory operationwill always be carried out atomically:
      P6系列处理器(以及以后生产的处理器)确保以下对基本存储器的操作行为为原子操作:
      Unaligned 16-, 32-, and 64-bit accesses to cached memory that fit within a cache line
      对单个cache line中缓存地址的未对齐的16/32/64位访问(非对齐的数据访问非常影响性能)
      Accesses to cacheable memory that are split across cache lines and page boundaries are not guaranteed to beatomic by the Intel Core 2 Duo, Intel®Atom™, Intel Core Duo, Pentium M, Pentium 4, Intel Xeon, P6 family, Pentium, and Intel486 processors. The Intel Core 2 Duo, Intel Atom, Intel Core Duo, Pentium M, Pentium 4, IntelXeon, and P6 family processors provide bus control signals that permit external memory subsystems to make splitaccesses atomic; however, nonaligned data accesses will seriously impact the performance of the processor andshould be avoided.
     那些被总线带宽、cache line以及page大小给分隔开了的内存地址的访问不是原子的,你如果想保证这些操作是原子的,你就得求助于机制Bus Lock,对总线发出相应的控制信号才行。
      An x87 instruction or an SSE instructions that accesses data larger than a quadword may be implemented usingmultiple memory accesses. If such an instruction stores to memory, some of the accesses may complete (writingto memory) while another causes the operation to fault for architectural reasons (e.g. due an page-table entry thatis marked “not present”). In this case, the effects of the completed accesses may be visible to software eventhough the overall instruction caused a fault. If TLB invalidation has been delayed (see Section 4.10.4.4), suchpage faults may occur even if all accesses are to the same page.

     在intel处理器上c++中一些基本的运算那些是基本操作?(本人CPU为Intel Core i5-4590 3.3GHz, x, y均为int型)

操作
反汇编代码(VS2010)                    
++imov         eax,dword ptr [i]  
add         eax,1  
mov         dword ptr [i],eaxi++mov         eax,dword ptr [i]  
add         eax,1  
mov         dword ptr [i],eaxx = ymov         eax,dword ptr [y]  
mov         dword ptr [x],eaxx = 1mov         dword ptr [x],1 x + ymov         eax,dword ptr [x]  
add         eax,dword ptr [y]x + 1mov         eax,dword ptr [x]  
add         eax,1x += ymov         eax,dword ptr [x]  
add         eax,dword ptr [y]  
mov         dword ptr [x],eaxx += 1mov         eax,dword ptr [x]  
add         eax,1  
mov         dword ptr [x],eax x - ymov         eax,dword ptr [x]  
sub         eax,dword ptr [y] x - 1mov         eax,dword ptr [x]  
sub         eax,1x -= ymov         eax,dword ptr [x]  
sub         eax,dword ptr [y]  
mov         dword ptr [x],eaxx -= 1mov         eax,dword ptr [x]  
sub         eax,1  
mov         dword ptr [x],eaxx * ymov         eax,dword ptr [x]  
imul        eax,dword ptr [y]x * 10(x*1和x*2会被优化)mov         eax,dword ptr [x]  
imul        eax,eax,0Ahx *= ymov         eax,dword ptr [x]  
imul        eax,dword ptr [y]  
mov         dword ptr [x],eaxx *= 10mov         eax,dword ptr [x]  
imul        eax,eax,0Ah  
mov         dword ptr [x],eaxx / ymov         eax,dword ptr [x]  
cdq  
idiv        eax,dword ptr [y]x / 10mov         eax,dword ptr [x]  
cdq  
mov         ecx,0Ah  
idiv        eax,ecx10 / xmov         eax,0Ah  
cdq  
idiv        eax,dword ptr [x]x /= ymov         eax,dword ptr [x]  
cdq  
idiv        eax,dword ptr [y]  
mov         dword ptr [x],eaxx /= 10mov         eax,dword ptr [x]  
cdq  
mov         ecx,0Ah  
idiv        eax,ecx  
mov         dword ptr [x],eaxx % ymov         eax,dword ptr [x]  
cdq  
idiv        eax,dword ptr [y]x % 10mov         eax,dword ptr [x]  
cdq  
mov         ecx,0Ah  
idiv        eax,ecxx %= ymov         eax,dword ptr [x]  
cdq  
idiv        eax,dword ptr [y]  
mov         dword ptr [x],edxx %= 10mov         eax,dword ptr [x]  
cdq  
mov         ecx,0Ah  
idiv        eax,ecx  
mov         dword ptr [x],edxx >> ymov         eax,dword ptr [x]  
mov         ecx,dword ptr [y]  
sar         eax,clx >> 1mov         eax,dword ptr [x]  
sar         eax,1x << ymov         eax,dword ptr [x]  
mov         ecx,dword ptr [y]  
shl         eax,clx << 1mov         eax,dword ptr [x]  
shl         eax,1x >>= ymov         eax,dword ptr [x]  
mov         ecx,dword ptr [y]  
sar         eax,cl  
mov         dword ptr [x],eaxx >>= 1mov         eax,dword ptr [x]  
sar         eax,1  
mov         dword ptr [x],eaxx <<= ymov         eax,dword ptr [x]  
mov         ecx,dword ptr [y]  
shl         eax,cl  
mov         dword ptr [x],eaxx <<= 1mov         eax,dword ptr [x]  
shl         eax,1  
mov         dword ptr [x],eaxx & ymov         eax,dword ptr [x]  
and         eax,dword ptr [y]x & 10mov         eax,dword ptr [x]  
and         eax,0Ahx &= ymov         eax,dword ptr [x]  
and         eax,dword ptr [y]  
mov         dword ptr [x],eaxx &= 10mov         eax,dword ptr [x]  
and         eax,0Ah  
mov         dword ptr [x],eaxx | ymov         eax,dword ptr [x]  
or          eax,dword ptr [y] x | 10mov         eax,dword ptr [x]  
or          eax,0Ahx |= ymov         eax,dword ptr [x]  
or          eax,dword ptr [y]  
mov         dword ptr [x],eaxx |= 10mov         eax,dword ptr [x]  
or          eax,0Ah  
mov         dword ptr [x],eaxx ^ ymov         eax,dword ptr [x]  
xor         eax,dword ptr [y] x ^ 10mov         eax,dword ptr [x]  
xor         eax,0Ahx ^= ymov         eax,dword ptr [x]  
xor         eax,dword ptr [y]  
mov         dword ptr [x],eaxx ^= 10mov         eax,dword ptr [x]  
xor         eax,0Ah  
mov         dword ptr [x],eax!xxor         eax,eax  
cmp         dword ptr [x],0  
sete        al~xmov         eax,dword ptr [x]  
not         eax从图表中看出就 x = 1为一条汇编操作指令。那我们再来看下不同类型下的的值为x赋值的结果:

类型反汇编代码(vs2010)char x = 10;mov         byte ptr [x],0Ahunsigned char x = 10;mov         byte ptr [x],0Ahshort x = 10;mov         eax,0Ah  
mov         word ptr [x],axunsigned short x = 10;mov         eax,0Ah  
mov         word ptr [x],axint x = 10;mov         dword ptr [x],0Ahunsigned int x = 10;mov         dword ptr [x],0Ahlong x = 10;mov         dword ptr [x],0Ahunsigned long x = 10;mov         dword ptr [x],0Ahlong long x = 0xFFFFFFFFFFFF;mov         dword ptr [x],0FFFFFFFFh  
mov         dword ptr [ebp-8],0FFFFhunsigned long long x = 0xFFFFFFFFFFFF;mov         dword ptr [x],0FFFFFFFFh  
mov         dword ptr [ebp-8],0FFFFhfloat x = 10.20;fld         dword ptr [__real@41233333 (0F6311Ch)]  
fstp        dword ptr [x]double x = 10.20;fld         qword ptr [__real@4024666666666666 (13D3120h)]  
fstp        qword ptr [x]__int8 x = 10;
mov         byte ptr [x],0Ah
__int16 x = 10;
mov         eax,0Ah  
mov         word ptr [x],ax
__int32 x = 10;
mov         dword ptr [x],0Ah 
__int64 x = 0xFFFFFFFFFFFF;
mov         dword ptr [x],0FFFFFFFFh  
mov         dword ptr [ebp-8],0FFFFh

C++中线程同步


什么情况需要线程同步

1、有两个或两个以上的线程对同一份数进行操作,而且这些线程中存在写操作。

2、每个线程对该数据的操作完成后才能进行其他线程对该数据的操作,也就是乱序会对数据产生”撕裂“或数据难以预料。

比如说一个结构体重有两个成员变量{int x; int y;}, 如果一个线程对该结构体的实例进行写操作{x = 1, y = 2},另一个也进行写操作{x = 3, y = 4};如果没有进行线程同步,会存在如下几种情况:

x = 1y =2x = 1y =4x = 3y =2x = 3y = 4这样会造成数据的”撕裂“,从而需要我们进行线程同步保证数据要么是{x = 1, y = 2},要么是{x = 3, y = 4}

在C++中面对内建类型的多线程同步,非原子操作并不一定需要线程同步


操作反汇编代码(VS2010)  
说明                                                
同步?
++imov         eax,dword ptr [i]  
add         eax,1  
mov         dword ptr [i],eax存在对同一数据的读写, 乱序会造成数据异常需要i++mov         eax,dword ptr [i]  
add         eax,1  
mov         dword ptr [i],eax同上需要x = ymov         eax,dword ptr [y]  
mov         dword ptr [x],eax非对同一数据的读写,而且乱序不会对数据结果产生影响不需要x = 1mov         dword ptr [x],1 本来就是原子操作不需要x + ymov         eax,dword ptr [x]  
add         eax,dword ptr [y]x + y不赋值给其他变量是没有意义的,不做讨论 x + 1mov         eax,dword ptr [x]  
add         eax,1不赋值给其他变量是没有意义的,不做讨论 x += ymov         eax,dword ptr [x]  
add         eax,dword ptr [y]  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x += 1mov         eax,dword ptr [x]  
add         eax,1  
mov         dword ptr [x],eax 存在对同一数据的读写, 乱序会造成数据异常需要x - ymov         eax,dword ptr [x]  
sub         eax,dword ptr [y] 不赋值给其他变量是没有意义的,不做讨论 x - 1mov         eax,dword ptr [x]  
sub         eax,1不赋值给其他变量是没有意义的,不做讨论 x -= ymov         eax,dword ptr [x]  
sub         eax,dword ptr [y]  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x -= 1mov         eax,dword ptr [x]  
sub         eax,1  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x * ymov         eax,dword ptr [x]  
imul        eax,dword ptr [y]不赋值给其他变量是没有意义的,不做讨论 x * 10(x*1和x*2会被优化)mov         eax,dword ptr [x]  
imul        eax,eax,0Ah不赋值给其他变量是没有意义的,不做讨论 x *= ymov         eax,dword ptr [x]  
imul        eax,dword ptr [y]  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x *= 10mov         eax,dword ptr [x]  
imul        eax,eax,0Ah  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x / ymov         eax,dword ptr [x]  
cdq  
idiv        eax,dword ptr [y]不赋值给其他变量是没有意义的,不做讨论 x / 10mov         eax,dword ptr [x]  
cdq  
mov         ecx,0Ah  
idiv        eax,ecx不赋值给其他变量是没有意义的,不做讨论 10 / xmov         eax,0Ah  
cdq  
idiv        eax,dword ptr [x]不赋值给其他变量是没有意义的,不做讨论 x /= ymov         eax,dword ptr [x]  
cdq  
idiv        eax,dword ptr [y]  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x /= 10mov         eax,dword ptr [x]  
cdq  
mov         ecx,0Ah  
idiv        eax,ecx  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x % ymov         eax,dword ptr [x]  
cdq  
idiv        eax,dword ptr [y]不赋值给其他变量是没有意义的,不做讨论 x % 10mov         eax,dword ptr [x]  
cdq  
mov         ecx,0Ah  
idiv        eax,ecx不赋值给其他变量是没有意义的,不做讨论 x %= ymov         eax,dword ptr [x]  
cdq  
idiv        eax,dword ptr [y]  
mov         dword ptr [x],edx存在对同一数据的读写, 乱序会造成数据异常需要x %= 10mov         eax,dword ptr [x]  
cdq  
mov         ecx,0Ah  
idiv        eax,ecx  
mov         dword ptr [x],edx存在对同一数据的读写, 乱序会造成数据异常需要x >> ymov         eax,dword ptr [x]  
mov         ecx,dword ptr [y]  
sar         eax,cl不赋值给其他变量是没有意义的,不做讨论 x >> 1mov         eax,dword ptr [x]  
sar         eax,1不赋值给其他变量是没有意义的,不做讨论 x << ymov         eax,dword ptr [x]  
mov         ecx,dword ptr [y]  
shl         eax,cl不赋值给其他变量是没有意义的,不做讨论 x << 1mov         eax,dword ptr [x]  
shl         eax,1不赋值给其他变量是没有意义的,不做讨论 x >>= ymov         eax,dword ptr [x]  
mov         ecx,dword ptr [y]  
sar         eax,cl  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x >>= 1mov         eax,dword ptr [x]  
sar         eax,1  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x <<= ymov         eax,dword ptr [x]  
mov         ecx,dword ptr [y]  
shl         eax,cl  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x <<= 1mov         eax,dword ptr [x]  
shl         eax,1  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x & ymov         eax,dword ptr [x]  
and         eax,dword ptr [y]不赋值给其他变量是没有意义的,不做讨论 x & 10mov         eax,dword ptr [x]  
and         eax,0Ah不赋值给其他变量是没有意义的,不做讨论 x &= ymov         eax,dword ptr [x]  
and         eax,dword ptr [y]  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x &= 10mov         eax,dword ptr [x]  
and         eax,0Ah  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x | ymov         eax,dword ptr [x]  
or          eax,dword ptr [y] 不赋值给其他变量是没有意义的,不做讨论 x | 10mov         eax,dword ptr [x]  
or          eax,0Ah不赋值给其他变量是没有意义的,不做讨论 x |= ymov         eax,dword ptr [x]  
or          eax,dword ptr [y]  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x |= 10mov         eax,dword ptr [x]  
or          eax,0Ah  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x ^ ymov         eax,dword ptr [x]  
xor         eax,dword ptr [y] 不赋值给其他变量是没有意义的,不做讨论 x ^ 10mov         eax,dword ptr [x]  
xor         eax,0Ah不赋值给其他变量是没有意义的,不做讨论 x ^= ymov         eax,dword ptr [x]  
xor         eax,dword ptr [y]  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要x ^= 10mov         eax,dword ptr [x]  
xor         eax,0Ah  
mov         dword ptr [x],eax存在对同一数据的读写, 乱序会造成数据异常需要!xxor         eax,eax  
cmp         dword ptr [x],0  
sete        al不赋值给其他变量是没有意义的,不做讨论 ~xmov         eax,dword ptr [x]  
not         eax不赋值给其他变量是没有意义的,不做讨论 

对内建类型变量的赋值(数值):

类型反汇编代码(vs2010)说明                            
同步?       
char x = 10;mov         byte ptr [x],0Ah原子操作不需要unsigned char x = 10;mov         byte ptr [x],0Ah原子操作不需要short x = 10;mov         eax,0Ah  
mov         word ptr [x],ax只有一个写操作不需要unsigned short x = 10;mov         eax,0Ah  
mov         word ptr [x],ax只有一个写操作不需要int x = 10;mov         dword ptr [x],0Ah原子操作不需要unsigned int x = 10;mov         dword ptr [x],0Ah原子操作不需要long x = 10;mov         dword ptr [x],0Ah原子操作不需要unsigned long x = 10;mov         dword ptr [x],0Ah原子操作不需要long long x = 0xFFFFFFFFFFFF;mov         dword ptr [x],0FFFFFFFFh  
mov         dword ptr [ebp-8],0FFFFh写写操作需要unsigned long long x = 0xFFFFFFFFFFFF;mov         dword ptr [x],0FFFFFFFFh  
mov         dword ptr [ebp-8],0FFFFh写写操作需要float x = 10.20;fld         dword ptr [__real@41233333 (0F6311Ch)]  
fstp        dword ptr [x]只有一个写操作不需要double x = 10.20;fld         qword ptr [__real@4024666666666666 (13D3120h)]  
fstp        qword ptr [x]只有一个写操作不需要__int8 x = 10;
mov         byte ptr [x],0Ah
原子操作不需要__int16 x = 10;
mov         eax,0Ah  
mov         word ptr [x],ax
只有一个写操作不需要__int32 x = 10;
mov         dword ptr [x],0Ah 
原子操作不需要__int64 x = 0xFFFFFFFFFFFF;
mov         dword ptr [x],0FFFFFFFFh  
mov         dword ptr [ebp-8],0FFFFh
写写操作需要

对内建类型变量的赋值(变量):

类型反汇编代码(vs2010)说明                            
同步?       
char x = y;mov         al,byte ptr [y]  
mov         byte ptr [x],al非对同一数据的读写,而且乱序不会对数据结果产生影响不需要unsigned char x = y;mov         al,byte ptr [y]  
mov         byte ptr [x],al非对同一数据的读写,而且乱序不会对数据结果产生影响不需要short x = y;mov         ax,word ptr [y]  
mov         word ptr [x],ax非对同一数据的读写,而且乱序不会对数据结果产生影响不需要unsigned short x = y;mov         ax,word ptr [y]  
mov         word ptr [x],a非对同一数据的读写,而且乱序不会对数据结果产生影响不需要int x = y;mov         eax,dword ptr [y]  
mov         dword ptr [x],eax非对同一数据的读写,而且乱序不会对数据结果产生影响不需要unsigned int x = y;mov         eax,dword ptr [y]  
mov         dword ptr [x],eax非对同一数据的读写,而且乱序不会对数据结果产生影响不需要long x = y;mov         eax,dword ptr [y]  
mov         dword ptr [x],eax非对同一数据的读写,而且乱序不会对数据结果产生影响不需要unsigned long x = y;mov         eax,dword ptr [y]  
mov         dword ptr [x],eax非对同一数据的读写,而且乱序不会对数据结果产生影响不需要long long x = y;mov         eax,dword ptr [y]  
mov         dword ptr [x],eax  
mov         ecx,dword ptr [ebp-18h]  
mov         dword ptr [ebp-8],ecx对x存在写写操作,乱序会产出数据”撕裂“需要unsigned long long x = y;mov         eax,dword ptr [y]  
mov         dword ptr [x],eax  
mov         ecx,dword ptr [ebp-18h]  
mov         dword ptr [ebp-8],ecx对x存在写写操作,乱序会产出数据”撕裂“需要float x = y;fld         dword ptr [y]  
fstp        dword ptr [x]非对同一数据的读写,而且乱序不会对数据结果产生影响不需要double x = y;fld         qword ptr [y]  
fstp        qword ptr [x]非对同一数据的读写,而且乱序不会对数据结果产生影响需要__int8 x = y;
mov         al,byte ptr [y]  
mov         byte ptr [x],al
非对同一数据的读写,而且乱序不会对数据结果产生影响不需要__int16 x =y;
mov         ax,word ptr [y]  
mov         word ptr [x],ax
非对同一数据的读写,而且乱序不会对数据结果产生影响不需要__int32 x =y;
mov         eax,dword ptr [y]  
mov         dword ptr [x],eax
非对同一数据的读写,而且乱序不会对数据结果产生影响不需要__int64 x = y;
mov         eax,dword ptr [y]  
mov         dword ptr [x],eax  
mov         ecx,dword ptr [ebp-18h]  
mov         dword ptr [ebp-8],ecx
 需要



0 0
原创粉丝点击