C++ 原子内存顺序与线程事件如 notify()
C++ atomic memory order vs thread events such as notify()
两个线程共享一个原子布尔值"ready"。线程A正在做一些任务,线程B正在等待A的通知。任务完成后A会设置"ready"为True。
B 有一个测试 "ready" 的等待谓词。醒来时,如果 "ready" 仍然为 False,B 将返回等待。 (这可以防止虚假唤醒造成麻烦)
A 完成任务,将 "ready" 设置为 True,然后通知 B。
问题:我如何保证 B 将读取(加载)"ready" 为 True 而不是旧的 False?
atomic<bool> ready = false;
Thread A
do_something();
ready = true;
B_cond_var.notify_one();
Thread B:
B_cond_var.wait( mtx, []() -> bool { return ready == true; } );
do_something(); // <- sometimes doesn't happen
我发现有时 B 读 "ready" 为 False,并且永远不会醒来。这意味着从它的角度来看,通知在更新之前出现,即使在A中顺序是更新,然后通知。
注意:我已经阅读了太多有关内存排序保证的内容,而且我认为我对读写排序的理解足够了。然而这道题涉及到内存更新的顺序和线程通信事件,即notify。我找不到关于如何保证这些顺序的直接答案。
参见例如:
http://www.developerfusion.com/article/138018/memory-ordering-for-atomic-operations-in-c0x/
http://bartoszmilewski.com/2008/12/01/c-atomics-and-memory-ordering/
另见 C++11 标准第 29.3 节
更新:很抱歉造成混淆,以上只是伪代码,是从一个更大的主体中归纳出来的,我省略了一些不会进入问题的东西,比如条件变量上存在互斥锁。工作代码展示了所描述的变量更新的重新排序,并在运行时大约每 400 天通知一次——实际上每天 3-4 次。这 是 实际发生的。
如果你用条件变量保护它,你就不需要原子变量。但是,条件变量需要互斥锁,而我在这段代码中没有看到互斥锁。您的 lambda missess return 语句也是如此。
正确使用条件变量会给你想要的结果。
内存排序在这里完全不相关,因为所有 Posix 线程同步原语都强加了完整的内存屏障。
两个线程共享一个原子布尔值"ready"。线程A正在做一些任务,线程B正在等待A的通知。任务完成后A会设置"ready"为True。
B 有一个测试 "ready" 的等待谓词。醒来时,如果 "ready" 仍然为 False,B 将返回等待。 (这可以防止虚假唤醒造成麻烦)
A 完成任务,将 "ready" 设置为 True,然后通知 B。
问题:我如何保证 B 将读取(加载)"ready" 为 True 而不是旧的 False?
atomic<bool> ready = false;
Thread A
do_something();
ready = true;
B_cond_var.notify_one();
Thread B:
B_cond_var.wait( mtx, []() -> bool { return ready == true; } );
do_something(); // <- sometimes doesn't happen
我发现有时 B 读 "ready" 为 False,并且永远不会醒来。这意味着从它的角度来看,通知在更新之前出现,即使在A中顺序是更新,然后通知。
注意:我已经阅读了太多有关内存排序保证的内容,而且我认为我对读写排序的理解足够了。然而这道题涉及到内存更新的顺序和线程通信事件,即notify。我找不到关于如何保证这些顺序的直接答案。
参见例如: http://www.developerfusion.com/article/138018/memory-ordering-for-atomic-operations-in-c0x/
http://bartoszmilewski.com/2008/12/01/c-atomics-and-memory-ordering/
另见 C++11 标准第 29.3 节
更新:很抱歉造成混淆,以上只是伪代码,是从一个更大的主体中归纳出来的,我省略了一些不会进入问题的东西,比如条件变量上存在互斥锁。工作代码展示了所描述的变量更新的重新排序,并在运行时大约每 400 天通知一次——实际上每天 3-4 次。这 是 实际发生的。
如果你用条件变量保护它,你就不需要原子变量。但是,条件变量需要互斥锁,而我在这段代码中没有看到互斥锁。您的 lambda missess return 语句也是如此。
正确使用条件变量会给你想要的结果。
内存排序在这里完全不相关,因为所有 Posix 线程同步原语都强加了完整的内存屏障。