例如,如果我们有两个 std::atomic
并且想要从第一个读取值然后标记第二个我们不再需要第一个的值。我们不希望这些操作被重新排序(否则第一个值可以在我们读取之前被重写),但是操作之间没有数据依赖性,所以我们明确需要一个屏障来防止重新排序(和 memory_order_consume
不适合)。
全栅栏在这里肯定是矫枉过正。此外,我们既不需要释放也不需要获得语义(即使它们提供了这样的障碍)。我们所需要的只是保留先读后写操作的顺序。
是否有一些廉价的栅栏可以满足我们的需求?
编辑:我需要的例子。
std::atomic<X> atomicVal;
std::atomic<bool> atomicFlag = false;
...
auto value = atomicVal.load(std::memory_order_relaxed);
some_appropriative_fence();
atomicFlag.store(true, std::memory_order_relaxed);
并且在 atomicFlag
被设置之后 atomicVal
可以被覆盖为一些进一步的值,所以我们需要在之前读取它。
当然可以
auto value = atomicVal.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
atomicFlag.store(true, std::memory_order_relaxed);
但是对于我们需要的操作来说它太昂贵了。
我很感兴趣,最小限度的栅栏足以保证操作顺序。
最佳答案
根据您的更新: https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering
你会希望原子标志和变量被写入(存储):
ptr.store(p, std::memory_order_release);
并且您希望通过以下方式读取标志和值:
p2 = ptr.load(std::memory_order_acquire)
这似乎就是它们存在的确切原因。
编辑 2:事实上,Release-Consume 可能更好。但我从未见过它被使用过。上面的链接还指出:
Note that currently (2/2015) no known production compilers track dependency chains: consume operations are lifted to acquire operations.
编辑 3:示例代码执行与我理解的您想要的类似的操作。
#include <thread>
#include <iostream>
#include <atomic>
std::atomic<int> x;
std::atomic<int> y;
auto write_op = std::memory_order_release;
auto read_op = std::memory_order_acquire;
// auto write_op = std::memory_order_seq_cst;
// auto read_op = std::memory_order_seq_cst;
void consumer()
{
while(true)
{
int rx,ry;
do
{
ry = y.load(read_op); // flag read first to guarantee x validity
rx = x.load(read_op);
}
while(ry == 0); // wait for y. y acts as the flag, here
if (ry == -1)
{
break;
}
if (rx != ry) // check consistency
{
std::cout << "Boo " << rx << " " << ry << std::endl;
}
x.store(0, write_op);
y.store(0, write_op);
}
}
void producer()
{
int count = 0;
int steps = 0;
while(steps < 50)
{
while(y.load(read_op) != 0) {} // wait for y to have been consumed
int value = std::rand() % 10 + 1;
x.store(value, write_op); // stores values
y.store(value, write_op); // indicates readiness to other thread
count++;
if (count == 1000000)
{
std::cout << '.' << std::endl;
count = 0;
steps++;
}
}
y.store(-1);
}
int main()
{
x = 0;
y = 0;
std::thread thread1(producer);
std::thread thread2(consumer);
thread1.join();
thread2.join();
}
关于c++ - 如何制作轻量级的加载-存储屏障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52855910/