单线程在多核处理器上的数据可见性

4
在单线程程序中,如果线程在核1中进行更改,如何使核2看到更改后的值,以便在上下文切换后,线程(现在在核2上运行)将具有更新的值?
考虑以下示例:
1.变量x在主存储器中的值为10。 2.线程在核1上运行,并将x更改为5,它仍然在缓存中,尚未刷新到主存储器,因为我们没有使用任何内存屏障。 3.发生上下文切换,线程从核1移动到核2。 4.线程读取x的值。
如果线程在上下文切换后在核2中恢复执行,x的值将是多少?
如果“缓存一致性”管理一致性以处理上述情况,那么为什么在多线程程序中需要显式锁定(或任何读/写屏障)?
1个回答

4
考虑到你的第一个问题,上下文切换也会保留寄存器内容。因此,线程将看到最新的值,即使移动到另一个核心(或CPU)。
然而,对于多线程程序,不同线程的CPU寄存器是不同的(无论线程在多少个核心上执行),而寄存器不属于缓存一致性。
因此,我认为,多线程程序确实需要确保寄存器中的值与主内存中的值是最新的。(缓存一致性只确保CPU缓存与内存是最新的)。因此,我想,你需要一个屏障来同步寄存器和内存。
你可以这样理解:程序实际上仅在主内存上运行。但编译器优化对主内存的访问并使用寄存器进行中间操作。因此,程序仅访问内存和寄存器。然而,CPU还引入了自己的内存缓存。从内存读取和写入都被CPU内部地优化为缓存。缓存一致性仅在CPU内部确保缓存是最新的(因此,访问内存的程序得到正确的值)。
总之:
- 缓存一致性确保缓存和内存是最新的,它超出了程序的控制范围,因为它是CPU内部的。 - 上下文切换由操作系统处理,它在将线程移动到不同的核心时确保寄存器的正确值。 - 内存屏障确保寄存器和内存是最新的,这是程序必须确保的。

1
我最初没有注意到在上下文切换时寄存器中的值会被复制。以下链接也很好地说明了这一点。 https://dev59.com/5W865IYBdhLWcg3wOb9h https://dev59.com/82PVa4cB1Zd3GeqP30H6 https://www.quora.com/Do-the-threads-within-a-process-have-their-own-registers-but-use-the-same-code-global-data-and-stack - javaq
这是否意味着,即使没有线程在同一堆级别的值上竞争,我们仍然需要使用同步来保证一致性?但这意味着我们必须在每个地方都保留内存屏障,对吗? - Ashok Koyi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接