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型作為條件判斷,可能會出來讀取出值后,值又被改變了的情況,這可能會導致執行本以不該被執行的代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM