c ++:原子变量的值在保存在局部变量中时无效
c++: atomic variable's value is invalid when saved in local variable
我在一些 Obj-C 文件中定义了原子变量 current:
std::atomic<long long> current;
之后启动:
current=4;
之后,该变量可以通过线程数访问。
一些线程像这样修改了变量:
current=(current.fetch_add(1))%4;
当其他线程以不同方式修改变量时:
current.fetch_add(1);
if(current>=4){
current=0;
}
最后执行下一行:
long long cs=current;
此时发生了一些奇怪的事情:在调试器中显示 cs 是 4 而 current 有不同的值,通常是 1。
我的期望是 cs 应该有 current 的最新值并且永远不应该大于 3。
我检查了 current 的所有其他实例;它们数量不多,并且在任何地方都可以正确使用。
我错过了什么?
原子值不是同步原语。可能的执行流程之一:
current.fetch_add(1); // T1
long long cs=current; // T2
if(current>=4){ // T1
current=0;
}
和
auto tmp = current.fetch_add(1); // T1
long long cs=current; // T2
current=tmp%4; // T1
解决方案是在 compare-exchange 中使用互斥锁或自旋锁。
这是在多线程环境下极有可能发生的场景。假设只有 2 个线程,我在这里称为 THREAD-2 的主线程和一个工作线程 THREAD-1。让我们从 current 的值为 3 开始,现在它被 THREAD-1 递增,而 THREAD-2 正在更新变量 cs.
THREAD-1: current.fetch_add(1);
THREAD-2: cs = current;
THREAD-1: if(current>=4){ current=0; }
如您所见,cs 在电流为 4 时获得它的值。
此外,这不是 objective-c 问题,这只是 C++ 问题。
我在一些 Obj-C 文件中定义了原子变量 current:
std::atomic<long long> current;
之后启动:
current=4;
之后,该变量可以通过线程数访问。 一些线程像这样修改了变量:
current=(current.fetch_add(1))%4;
当其他线程以不同方式修改变量时:
current.fetch_add(1);
if(current>=4){
current=0;
}
最后执行下一行:
long long cs=current;
此时发生了一些奇怪的事情:在调试器中显示 cs 是 4 而 current 有不同的值,通常是 1。 我的期望是 cs 应该有 current 的最新值并且永远不应该大于 3。 我检查了 current 的所有其他实例;它们数量不多,并且在任何地方都可以正确使用。 我错过了什么?
原子值不是同步原语。可能的执行流程之一:
current.fetch_add(1); // T1
long long cs=current; // T2
if(current>=4){ // T1
current=0;
}
和
auto tmp = current.fetch_add(1); // T1
long long cs=current; // T2
current=tmp%4; // T1
解决方案是在 compare-exchange 中使用互斥锁或自旋锁。
这是在多线程环境下极有可能发生的场景。假设只有 2 个线程,我在这里称为 THREAD-2 的主线程和一个工作线程 THREAD-1。让我们从 current 的值为 3 开始,现在它被 THREAD-1 递增,而 THREAD-2 正在更新变量 cs.
THREAD-1: current.fetch_add(1);
THREAD-2: cs = current;
THREAD-1: if(current>=4){ current=0; }
如您所见,cs 在电流为 4 时获得它的值。
此外,这不是 objective-c 问题,这只是 C++ 问题。