我在en.cppreference.com 规范中阅读了关于原子的宽松操作:
“[...]只保证原子性和修改顺序 的一致性。”
所以,我在问自己,当您处理相同或不同的原子变量时,这种“修改顺序”是否有效。
在我的代码中,我有一个原子树,其中一个低优先级、基于事件的消息线程填充了应该更新的节点,将一些数据存储在红色“1”原子(见图)上,使用memory_order_relaxed
. 然后它继续使用 fetch_or 在其父级中写入以了解哪个子原子已被更新。每个原子最多支持 64 位,因此我将位 1 填充为红色操作“2”。它一直持续到根原子,它也使用 fetch_or 进行标记,但使用 time memory_order_release
。
然后一个快速、实时、不可阻塞的线程加载控制原子(使用memory_order_acquire
)并读取启用它的位。然后它递归地更新孩子的原子memory_order_relaxed
。这就是我将数据与高优先级线程的每个周期同步的方式。
由于该线程正在更新,因此可以将子原子存储在其父级之前。问题是在我填写子信息之前它存储了一个父项(填充要更新的子项)。
换句话说,正如标题所说,宽松的商店在发布之前是否在它们之间重新排序?我不介意对非原子变量进行重新排序。伪代码,假设 [x, y, z, control] 是原子的并且初始值为 0:
Event thread:
z = 1; // relaxed
y = 1; // relaxed
x = 1; // relaxed;
control = 0; // release
Real time thread (loop):
load control; // acquire
load x; // relaxed
load y; // relaxed
load z; // relaxed
我想知道在实时线程中这是否总是正确的:x <= y <=z。要检查我是否编写了这个小程序:
#define _ENABLE_ATOMIC_ALIGNMENT_FIX 1
#include <atomic>
#include <iostream>
#include <thread>
#include <assert.h>
#include <array>
using namespace std;
constexpr int numTries = 10000;
constexpr int arraySize = 10000;
array<atomic<int>, arraySize> tat;
atomic<int> tsync {0};
void writeArray()
{
// Stores atomics in reverse order
for (int j=0; j!=numTries; ++j)
{
for (int i=arraySize-1; i>=0; --i)
{
tat[i].store(j, memory_order_relaxed);
}
tsync.store(0, memory_order_release);
}
}
void readArray()
{
// Loads atomics in normal order
for (int j=0; j!=numTries; ++j)
{
bool readFail = false;
tsync.load(memory_order_acquire);
int minValue = 0;
for (int i=0; i!=arraySize; ++i)
{
int newValue = tat[i].load(memory_order_relaxed);
// If it fails, it stops the execution
if (newValue < minValue)
{
readFail = true;
cout << "fail " << endl;
break;
}
minValue = newValue;
}
if (readFail) break;
}
}
int main()
{
for (int i=0; i!=arraySize; ++i)
{
tat[i].store(0);
}
thread b(readArray);
thread a(writeArray);
a.join();
b.join();
}
它是如何工作的:有一个原子数组。一个线程以相反的顺序以宽松的顺序存储,并以释放顺序存储一个控制原子。
另一个线程加载控制原子的获取顺序,然后以放松的原子加载数组的其余值。由于父母不能在孩子之前更新,所以 newValue 应该总是等于或大于 oldValue。
我已经在我的电脑上多次执行了这个程序,调试和发布,它并没有触发失败。我使用的是普通的 x64 Intel i7 处理器。
那么,假设对多个原子的宽松存储至少在与控制原子同步并获取/释放时确实保持“修改顺序”是安全的吗?