C++中简单类型bool变量的原子性

这个问题实际上跟平台有很大的相关性。我们可以从汇编来看。

linux(x86)平台:

int main()
{
  bool f = true;
  if (f)
  {
    f = false;
  }
  return 0;
}
(gdb) list
1    int main()
2    {
3      bool f = true;
4      if (f)
5      {
6        f = false;
7      }
8      return 0;
9    }
(gdb) b 4
Breakpoint 1 at 0x602: file ../src/Test.cpp, line 4.
(gdb) r
Starting program: /home/ubuntu/workspace/Test/Debug/Test 

Breakpoint 1, main () at ../src/Test.cpp:4
4      if (f)
(gdb) disassemble 
Dump of assembler code for function main():
   0x00005555555545fa <+0>:    push   %rbp
   0x00005555555545fb <+1>:    mov    %rsp,%rbp
   0x00005555555545fe <+4>:    movb   $0x1,-0x1(%rbp)
=> 0x0000555555554602 <+8>:    cmpb   $0x0,-0x1(%rbp)
   0x0000555555554606 <+12>:    je     0x55555555460c <main()+18>
   0x0000555555554608 <+14>:    movb   $0x0,-0x1(%rbp)
   0x000055555555460c <+18>:    mov    $0x0,%eax
   0x0000555555554611 <+23>:    pop    %rbp
   0x0000555555554612 <+24>:    retq   
End of assembler dump.

从以上代码可以看到,对bool型的赋值操作 movb $0x1,-0x1(%rbp) 和对bool型的比较操作 cmpb $0x0,-0x1(%rbp) 都是一条汇编指令,可以认为是原子操作。

 

linux(arm)平台:

1 int main()
2 {
3   bool f = true;
4   if (f)
5   {
6     f = false;
7   }
8   return 0;
9 }
(gdb) list
1
2
3       int main()
4       {
5         bool f = true;
6         if (f)
7         {
8           f = false;
9         }
10        return 0;
(gdb) b 6
Breakpoint 1 at 0x4005ac: file test.cpp, line 6.
(gdb) r
Starting program: /home/ubuntu/workspace/test/test

Breakpoint 1, main () at test.cpp:6
6         if (f)
(gdb) disassemble
Dump of assembler code for function main():
   0x00000000004005a0 <+0>:     sub     sp, sp, #0x10
   0x00000000004005a4 <+4>:     mov     w0, #0x1                        // #1
   0x00000000004005a8 <+8>:     strb    w0, [sp,#15]
=> 0x00000000004005ac <+12>:    ldrb    w0, [sp,#15]
   0x00000000004005b0 <+16>:    cmp     w0, #0x0
   0x00000000004005b4 <+20>:    b.eq    0x4005bc <main()+28>
   0x00000000004005b8 <+24>:    strb    wzr, [sp,#15]
   0x00000000004005bc <+28>:    mov     w0, #0x0                        // #0
   0x00000000004005c0 <+32>:    add     sp, sp, #0x10
   0x00000000004005c4 <+36>:    ret
End of assembler dump.

从以上代码可以看到,对bool型的赋值操作 strb w0, [sp,#15] ,读取操作 ldrb w0, [sp,#15] 和比较操作 cmp w0, #0x0 均是原子操作。但是,与x86不同的是,在arm上,读取与比较是分开的。所以多线程编程时,以bool型作为条件判断,可能会出来读取出值后,值又被改变了的情况,这可能会导致执行本以不该被执行的代码。

posted @ 2021-04-27 11:48  倾越  阅读(1952)  评论(0编辑  收藏  举报