背景
我一直在阅读各种书籍和文章,以了解并发执行环境中的处理器缓存,缓存一致性和内存障碍。到目前为止,我一直无法确定我的常见编码实践是否在最严格的意义上是安全的。
假设
以下伪代码在双处理器机器上执行:
int sharedVar = 0;
myThread()
{
print(sharedVar);
}
main()
{
sharedVar = 1;
spawnThread(myThread);
sleep(-1);
}
main()在处理器1(P1)上执行,而myThread()在P2上执行。
最初,sharedVar存在于P1和P2的缓存中,初始值为0(由于某些“预热代码”未在上面显示。)
问题
严格来说 - 最好不要假设任何特定类型的CPU - myThread()保证打印1?
凭借我对处理器缓存的新发现,似乎完全有可能在print()语句时,P2可能没有收到由main()中的P1赋值引起的sharedVar的失效请求。因此,myThread()似乎可以打印0。
参考
这些是我一直在阅读的相关文章和书籍:
答案 0 :(得分:1)
严格来说 - 最好不要假设任何特定类型的CPU - myThread()保证打印1?
从理论上讲,它可以打印0
或1
,即使在x86上,也可以打印stores can move after loads on almost any architecture。
在实践中,很难让myThread()
打印0
产生一个线程很可能会起到隐式存储/释放memory barrier的作用,因为它可能会:
- 在执行路径上至少有一条指令导致内存屏障 - 互锁指令,显式内存屏障指令等,
- 或者在调用myThread()
时,商店只会从store buffer退出/消失,因为设置新线程会导致执行许多指令 - 其中包括许多商店。
答案 1 :(得分:0)
我只会在这里说 :myThread()
保证打印1,因为来自 Java语言规范的happens before definition (第17.4.5节)。
在sharedVar
中对main()
的写入发生在生成具有函数myThread()
的线程之前,因为变量赋值首先出现在程序顺序。接下来,在正在启动的线程中的任何操作之前发生线程。通过第17.4.5节中的定义的传递性( hb(x,y)和 hb(y,z)暗示 hb(x,z)< / em>),写入变量sharedVar
发生在 print()
读取sharedVar
中的myThread()
之前。
您可能也喜欢阅读Brian Goetz关于此主题的文章Java theory and practice: Fixing the Java Memory Model, Part 2,以及他的书Java Concurrency in Practice。