线程系统如何处理由不同cpu缓存的共享数据?

csj*_*csj 11 multithreading caching multiprocessor

我主要来自c ++背景,但我认为这个问题适用于任何语言的线程.这是场景:

  1. 我们有两个线程(ThreadA和ThreadB),共享内存中有一个值x

  2. 假设通过互斥锁(或其他合适的同步控制)适当地控制对x的访问

  3. 如果线程碰巧在不同的处理器上运行,如果ThreadA执行写操作会发生什么,但是它的处理器将结果放在其L2缓存中而不是主内存中?然后,如果ThreadB尝试读取该值,它不仅会查看自己的L1/L2缓存/主内存,然后使用旧的值吗?

如果不是这样,那么这个问题是如何管理的?

如果是这样的话,那么可以采取什么措施呢?

Mic*_*ael 12

你的例子可以正常工作.

多个处理器使用一致性协议(如MESI)来确保数据在高速缓存之间保持同步.使用MESI,每个缓存行被认为是经过修改,独占,在CPU之间共享或无效.编写在处理器之间共享的高速缓存行会强制它在其他CPU中变为无效,从而使高速缓存保持同步.

但是,这还不够.不同的处理器具有不同的存储器模型,并且大多数现代处理器支持某种程度的重新排序存储器访问.在这些情况下,需要内存障碍.

例如,如果你有线程A:

DoWork();
workDone = true;
Run Code Online (Sandbox Code Playgroud)

和线程B:

while (!workDone) {}
DoSomethingWithResults()
Run Code Online (Sandbox Code Playgroud)

由于两者都在不同的处理器上运行,因此无法保证在写入workDone和DoSomethingWithResults()之前,DoWork()内完成的写入对线程B可见,并且可能会出现可能不一致的状态.内存屏障保证了读写的一些顺序 - 在线程A中的DoWork()之后添加内存屏障会强制DoWork完成的所有读/写操作在写入workDone之前完成,以便线程B获得一致的视图.互斥锁本身就提供了一个内存屏障,因此读/写不能通过锁定和解锁的调用.

在您的情况下,一个处理器会向其他处理器发出信号,表示它弄脏了缓存行,并强制其他处理器从内存重新加载.获取互斥锁以读取和写入值可确保按预期顺序对其他处理器显示对内存的更改.