首页 > 代码库 > 多线程读取全局变量 (在无锁状态下 会造成多少种值的出现)

多线程读取全局变量 (在无锁状态下 会造成多少种值的出现)

int global = 0;

// thread 1
for(int i = 0; i < 10; ++i)
global -= 1;

// thread 2
for(int i = 0; i < 10; ++i)
global += 1;
之后global的可能的值是多少(多种可能)?

 

  这个问题考虑的是全局变量global的加减操作不是原子操作,在加减过程中有可能被打断,从而产生的结果与预期不一样。上述global加减操作的汇编如下

;windows下加操作
mov eax,dword ptr [globle (10A9148h)] 
add eax,1 
mov dword ptr [globle (10A9148h)],eax 

;windows下减操作
mov eax,dword ptr [globle (10A9148h)] 
sub eax,1 
mov dword ptr [globle (10A9148h)],eax 

;linux下加操作
movl global, %eax
addl $1, %eax
movl %eax, global

;linux下减操作
movl global, %eax
subl $1, %eax
movl %eax, global

可见,不论加减都要经过global的值加载到eax,然后eax加减1,最后再写回global中。这时如果线程1的global的值刚加载到eax中,线程2获取到了执行权,就会出现问题。具体看下面例子。

  假设操作前global值为5。

  线程1                                                                                                                  线程2

  movl global,%eax;global值为5,%eax值为5

  addl $1,%eax;%eax值为6

                                                                   ------此时线程2获取执行权限--------->

                                                                                                                           movl global,%eax;global值为5,%eax值为5

                                                                                                                           subl $1,%eax;%eax值为4

                                                                                                                           movl %eax,global;%eax值为4,global值为4

                                                                 <--------执行权交回线程1-------------- 

  movl %eax,global;%eax值为4,global值为4

  由上述例子可以看出,结果并非我们预计的global的值加1减1后仍保持原值,而是由5变为了4。这就是多线程下非原子操作有可能产生的问题。

  所以题目global输出并非0一种可能。global的加减操作有可能失效,所以global的结果应分布在-10到10之间。

需要明白的对于硬件来说,虽说在操作一个值global,但是寄存器只有一个,如果不使用锁的时候,两个线程读取的都是同一个寄存器。这样会造成全局值的值很多种




多线程读取全局变量 (在无锁状态下 会造成多少种值的出现)