在大多数常见平台上(最重要的是x86;我明白有些平台有极其困难的内存模型,几乎没有保证对多线程有用,但我不关心罕见的反例),是以下代码安全
主题1:
someVariable = doStuff();
atomicSet(stuffDoneFlag, 1);
主题2:
while(!atomicRead(stuffDoneFlag)) {} // Wait for stuffDoneFlag to be set.
doMoreStuff(someVariable);
假设原子操作的标准合理实现:
someVariable
的分配是否保证在调用atomicSet()
之前完成?someVariable
之前看到doMoreStuff()
的作业,前提是它原子地读取stuffDoneFlag
吗?编辑:
LOCK
指令
操作,如果有帮助。stuffDoneFlag
以某种方式正确清除。怎么不重要。答案 0 :(得分:2)
如果您的实际x86代码在Thread 1中的atomicSet中存储到someVariable,并且在Thread 2中的atomicRead中加载之后加载someVariable,那么您应该没问题。 Intel's Software Developer's Manual Volume 3A在8.2节中指定了x86的内存模型,这里的线程内存储和负载加载约束就足够了。
但是,可能没有任何东西阻止您的编译器重新排序从您在原子操作中使用的任何更高级语言生成的指令。
答案 1 :(得分:0)
1)是
2)是
两者都有效。
答案 2 :(得分:0)
这段代码看起来是线程安全的,但我质疑你的spinlock(while循环)的效率,除非你只是在很短的时间内旋转。在任何给定的系统上都无法保证线程2不会完全占用所有处理时间。
我建议使用一些实际的同步原语(看起来像boost::condition_variable就是你想要的)而不是依赖于自旋锁。
答案 3 :(得分:0)
原子指令确保线程2在线程2继续之前等待线程1完成设置变量。但是,有两个关键问题:
1) someVariable
必须声明为“volatile”,以确保编译器不会优化它的分配,例如将其存储在寄存器中或推迟写入。
2)第二个线程在等待信号时阻塞(称为spinlocking)。您的平台可能提供了更好的锁定和信令主要和机制,但相对简单的改进只是在线程2的sleep()
主体中while()
。
答案 4 :(得分:0)
dsimcha写道:“假设stuffDoneFlag以某种方式被正确清除。多么重要。” 这不是真的!
让我们看看情景: