std::atomic<int> x;
int y;
void func_A()
{
y = 1;
x.store(42, std::memory_order_seq_cst); // "releases" y = 1
}
void func_B()
{
while (x.load(std::memory_order_relaxed) != 42) {} // does NOT "acquire" anything
assert(y == 1); // not guaranteed
}
int main()
{
std::thread a(&func_A), b(&func_B);
a.join();
b.join();
}
此处强制性说明:“* 它总是在我的机器上工作 *”并不能使它正确;如果没有同步,这就是数据竞争,一种undefined behavior形式。 但在您的特定情况下,如果您所说的wakeThreadB()是指用 Thread B 代码作为线程函数来构建std::thread示例,那么代码实际上是正确的-std::thread创建是一个同步事件(参见[thread.thread.constr]/5),因此 Thread B 中的任何加载都保证看到在 Thread B 启动之前完成的所有操作。 这意味着x的原子存储根本不重要,即使使用非原子int,代码也是正确的:
void func_B();
int x;
std::thread t;
void func_A()
{
x = 42;
t = std::thread(&func_B); // "releases" x = 42
}
void func_B() // "acquires" x = 42
{
assert(x == 42); // guaranteed success
}
int main()
{
func_A();
t.join();
}
2条答案
按热度按时间wlwcrazw1#
松弛加载不与其之前或之后的任何其他加载/存储同步。
还要注意,内存顺序语义是关于与syncronization变量相关的 * 其他工作 * 的可见性。
因此,例如,以下内容可能不正确:
此处强制性说明:“* 它总是在我的机器上工作 *”并不能使它正确;如果没有同步,这就是数据竞争,一种undefined behavior形式。
但在您的特定情况下,如果您所说的
wakeThreadB()
是指用 Thread B 代码作为线程函数来构建std::thread
示例,那么代码实际上是正确的-std::thread
创建是一个同步事件(参见[thread.thread.constr]/5),因此 Thread B 中的任何加载都保证看到在 Thread B 启动之前完成的所有操作。这意味着
x
的原子存储根本不重要,即使使用非原子int
,代码也是正确的:k5ifujac2#
如果直到
wakeThreadB()
Thread B
被锁定(如您所说,condional_variable
)std::memory_order_seq_cst
保证wakeThreadB()
不会在x.store
之前重新排序。因此,x.load
将在x.store
之后发生,因为在x.store
Thread B
锁定之前。assert(x_value == 42
)将在x.load(std::memory_order_relaxed)
之后发生,因为它不能由编译器重新排序,而不是因为内存顺序。