- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我试图证明不使用 std::atomic<>
是非常糟糕的主意s 但我无法创建一个重现失败的示例。我有两个线程,其中一个执行:
{
foobar = false;
}
和另一个:
{
if (foobar) {
// ...
}
}
foobar
的类型是 bool
或 std::atomic_bool
并初始化为 true
.我正在使用 OS X Yosemite,甚至尝试使用 this通过 CPU 亲和性暗示我希望线程在不同的内核上运行的技巧。我在循环等中运行这样的操作,在任何情况下,执行时都没有明显的差异。我最终用 clang clang -std=c++11 -lstdc++ -O3 -S test.cpp
检查生成的程序集我看到 read 上的 asm 差异很小(左边没有原子,右边有):
没有mfence
或“戏剧性”的东西。在写入方面,发生了一些更“戏剧性”的事情:
如您所见,atomic<>
版本使用 xchgb
它使用隐式锁。当我使用相对较旧版本的 gcc (v4.5.2) 编译时,我可以看到各种 mfence
添加 s 也表明存在严重问题。
我有点理解“X86 实现了非常强大的内存模型”(ref)和mfence
s 可能不是必需的,但这是否意味着除非我想编写跨平台代码,例如支持 ARM,我真的不需要放任何 atomic<>
除非我关心 ns 级别的一致性?
我看过"atomic<> Weapons"来自 Herb Sutter,但我仍然对创建一个重现这些问题的简单示例有多么困难印象深刻。
最佳答案
数据竞争的最大问题是它们是未定义的行为,不能保证错误的行为。这一点,再加上线程的普遍不可预测性和 x64 内存模型的强度,意味着很难创建可重现的故障。
一种稍微更可靠的故障模式是当优化器做出意想不到的事情时,因为您可以在程序集中观察到这些事情。当然,优化器也是出了名的挑剔,如果您只更改一行代码,它可能会做一些完全不同的事情。
这是我们的代码中曾经出现过的一个失败示例。代码实现了一种自旋锁,但没有使用原子。
bool operation_done;
void thread1() {
while (!operation_done) {
sleep();
}
// do something that depends on operation being done
}
void thread2() {
// do the operation
operation_done = true;
}
这在 Debug模式下运行良好,但发布版本卡住了。调试发现thread1的执行一直没有离开循环,查看程序集发现条件没有了;循环简直是无限的。
问题是优化器意识到在它的内存模型下,operation_done
不可能在循环内改变(那将是数据竞争),因此它“知道”一旦条件一次为真,永远为真。
将 operation_done 的类型更改为 atomic_bool
(或者实际上,C++11 之前编译器特定的等价物)解决了这个问题。
关于c++ - 多线程中是否需要原子类型? (OS X, clang, c++11),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39429056/
我是一名优秀的程序员,十分优秀!