var ++或var-- not threadsafe?

use*_*895 3 c++ increment nonblocking thread-safety

在C++中,我觉得我一直都认为像var ++和var--这样的东西是合理的线程安全的 - AKA - 你可以保证你的价值会在某个时间点增加或减少.

正是基于这种信念,我建立了对非线程算法的理解,以实现线程安全操作.然而,今天我感到震惊,因为我有一个没有增加的变量 - 因此我质疑我过去工作的大量有效性.

在一个小程序中,我有一个初始化为0的全局变量.启动了八个P-Threads,每个调用varname ++总共1024次,总计增加到8*1024.但是在所有线程完成执行后,varname的值明显小于8*1024.

我在这里错过了这条船吗?有人可以赐教吗?

Gri*_*zly 5

究竟是什么让你相信哪些线程安全?一般来说,他们不是.原因很简单:算术通常在寄存器上完成,因此var++可能会转换为如下所示:

load var to R1
inc R1
store R1 to var
Run Code Online (Sandbox Code Playgroud)

如果另一个线程var在加载和商店之间修改,您显然会松开该更新.实际上这个问题会更糟,因为编译器可以决定将变量保存在寄存器中只要它想要(只要它可以证明var不能通过任何指针访问它(在同一个指针中)线)).

让多个线程访问相同的变量被(C++ 11)标准定义为数据争用(因此是未定义的行为),除非线程没有修改变量(如果所有线程都只读取访问权限,你很好) .

对于线程安全操作,您需要使用锁定(例如std::mutex在C++ 11中使用)或原子操作.如果您使用C++ 11,您可以使用std::atomic<int>(或您的计数器的任何类型)作为var获得线程安全修改的类型.(算术)操作std::atomic<T>(如增量和减量运算符)保证是标准的线程安全.