Hol*_*Cat 21 c++ atomic memory-barriers stdatomic thread-sanitizer
我正在学习不同的记忆顺序。
\n我有这段代码,它可以工作并通过 GCC 和 Clang 的线程清理程序:
\n#include <atomic>\n#include <iostream>\n#include <future>\n \nint state = 0;\nstd::atomic_int a = 0;\n\nvoid foo(int from, int to) \n{\n for (int i = 0; i < 10; i++)\n {\n while (a.load(std::memory_order_acquire) != from) {}\n state++;\n a.store(to, std::memory_order_release);\n }\n}\n\nint main()\n{ \n auto x = std::async(std::launch::async, foo, 0, 1);\n auto y = std::async(std::launch::async, foo, 1, 0);\n}\nRun Code Online (Sandbox Code Playgroud)\n我认为如果它最终没有返回,则“获取”加载是不必要的from,那么“获取”负载是不必要的,因此我决定使用“宽松”负载,然后使用“获取”栅栏。
我期望它能工作,但它被线程清理程序拒绝了,线程清理程序声称并发state++是数据竞争。
#include <atomic>\n#include <iostream>\n#include <future>\n \nint state = 0;\nstd::atomic_int a = 0;\n\nvoid foo(int from, int to) \n{\n for (int i = 0; i < 10; i++)\n {\n while (a.load(std::memory_order_relaxed) != from) {}\n std::atomic_thread_fence(std::memory_order_acquire);\n state++;\n a.store(to, std::memory_order_release);\n }\n}\n\nint main()\n{ \n auto x = std::async(std::launch::async, foo, 0, 1);\n auto y = std::async(std::launch::async, foo, 1, 0);\n}\nRun Code Online (Sandbox Code Playgroud)\n为什么这是一场数据竞赛?
\n\n\n\n原子栅栏同步
\n线程 A 中的原子释放操作 X 与线程 B 中的获取栅栏 F 同步,如果
\n\n
\n- 存在原子读取 Y(具有任何内存顺序)
\n- Y读取X(或以X为首的释放序列)写入的值
\n- 在线程 B 中,Y 排序在 F 之前
\n在这种情况下,线程 A 中 X 之前排序的所有非原子和宽松原子存储将发生在线程 B 中 F 之后的相同位置的所有非原子和宽松原子加载之前。
\n
据我了解,满足所有条件:
\na.load(std::memory_order_relaxed)。a.store(to, std::memory_order_release);。Hol*_*Cat 19
线程清理程序当前不支持std::atomic_thread_fence. (GCC 和 Clang 使用相同的线程清理程序,因此它适用于两者。)
GCC 12(当前主干)对此发出警告:
atomic_base.h:133:26: warning: 'atomic_thread_fence' is not supported with '-fsanitize=thread' [-Wtsan]
133 | { __atomic_thread_fence(int(__m)); }
| ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
要阻止消毒剂忽略围栏,您可以使用__tsan_acquire和手动检测它们__tsan_release。
#include <sanitizer/tsan_interface.h>
while (a.load(std::memory_order_relaxed) != from) {}
__tsan_acquire(&a); // <--
std::atomic_thread_fence(std::memory_order_acquire);
Run Code Online (Sandbox Code Playgroud)
我认为自动确定哪些原子变量受到栅栏影响是很棘手的。
尽管错误报告说seq_cst栅栏不受影响__tsan_acquire,但如果我使用这样的栅栏,代码仍然会被拒绝,它们仍然需要用+注释__tsan_release,与 acq-rel fences 完全相同。
| 归档时间: |
|
| 查看次数: |
1244 次 |
| 最近记录: |