1

背景

我一直在阅读各种书籍和文章,以了解并发执行上下文中的处理器缓存、缓存一致性和内存屏障。但到目前为止,我一直无法确定我的常见编码实践在最严格的意义上是否安全。

假设

  1. 以下伪代码在双处理器机器上执行:

    int sharedVar = 0;
    
    myThread()
    {
        print(sharedVar);
    }
    
    main()
    {
        sharedVar = 1;
        spawnThread(myThread);
        sleep(-1);
    }
    
  2. main() 在处理器 1 (P1) 上执行,而 myThread() 在 P2 上执行。

  3. 最初,sharedVar 存在于 P1 和 P2 的缓存中,初始值为 0(由于上面未显示的一些“预热代码”。)

问题

严格来说——最好不假设任何特定类型的 CPU——myThread() 是否保证打印 1?

根据我对处理器缓存的新认识,在 print() 语句时,P2 可能没有收到由 P1 在 main() 中的分配导致的 sharedVar 无效请求,这似乎完全有可能。因此,myThread() 似乎有可能打印 0。

参考

这些是我一直在阅读的相关文章和书籍:

  1. 共享内存一致性模型:教程
  2. 内存屏障:软件黑客的硬件视图
  3. Linux 内核内存屏障
  4. 计算机体系结构:一种定量方法
4

2 回答 2

1

严格来说——最好不假设任何特定类型的 CPU——myThread() 是否保证打印 1?

理论上,它可以打印01,甚至在 x86 上,因为商店可以在几乎任何架构上加载后移动

在实践中,很难制作myThread()print 0
生成线程很可能充当隐式存储/释放内存屏障,因为它可能:
- 沿执行路径至少有一条指令导致内存屏障 - 互锁指令,显式内存屏障指令等,
-或者存储只是在调用时从存储缓冲区myThread()中退出/耗尽,因为设置一个新线程会导致执行许多指令 - 其中包括许多存储。

于 2010-06-09T18:51:35.237 回答
0

我在这里只讲JavamyThread()保证打印 1,因为发生在Java语言规范(第 17.4.5 节)的定义之前。

写入sharedVarinmain() 发生在使用函数生成线程之前,myThread()因为变量赋值在程序顺序中首先出现。接下来,在线程中的任何操作被启动之前产生一个线程。通过第 17.4.5 节中定义的传递性(hb(x, y)hb(y, z)意味着hb(x, z)),写入变量sharedVar 发生在 print()读入sharedVar之前myThread()

您可能还喜欢阅读 Brian Goetz 的文章Java 理论与实践:修复 Java 内存模型,第 2 部分涵盖该主题,以及他的书Java Concurrency in Practice

于 2010-06-06T14:39:12.410 回答