在I / O期间CPU缓存是否刷新到内存?

时间:2018-01-09 02:30:15

标签: caching x86 memory-model

假设我的服务器程序有两个在不同内核上运行的线程(T1和T2)。两者都通过网络从单个外部客户端提供RPC。发生以下操作序列:

  1. 内存变量foo初始化为零
  2. 客户端发送碰巧由T1提供的RPC,将foo设置为42
  3. T1将值写入foo,写入缓存在其核心的L1(非主存储器)中
  4. T1向客户端发送ACK
  5. 客户端发送正好由T2提供的RPC,以读取foo
  6. T2从缓存或主内存中读取foo并看到它为零
  7. T2回复客户说foo为零。
  8. 这违反了外部一致性。

    这实际上是否会发生,或者在执行将ACK发送回客户端的I / O时是否存在T1缓存的隐式刷新?(步骤4)?

3 个答案:

答案 0 :(得分:3)

在x86和x64系列上,所有缓存都是连贯的,即使两个线程不共享相同的缓存单元,你也会在T2上得到42。

您的思想实验可以进一步减少到2种情况:两个线程共享相同的缓存单元(多核)或不共享(多CPU)。

当他们共享一个缓存单元时,T1和T2都将使用相同的缓存,因此他们都会看到42而没有与内存同步。

如果不共享高速缓存(即,多CPU),则ISA要求高速缓存单元被同步,并且这对于软件是透明的。两个线程都会在同一地址看到42。这种同步虽然引入了一些开销,但是现在多核设计是首选(除了缓存昂贵的原因)。

答案 1 :(得分:3)

在步骤3,在T1修改值之前,它获取缓存行为“exclusive”,这意味着它不存在于任何其他线程的缓存中,并将缓存行状态设置为“modified”。

在步骤6,T2在其高速缓存中没有值,因此当它获取该值时,高速缓存一致性协议在T1的高速缓存中找到修改的行。高速缓存行的状态在T1的高速缓存和T2的高速缓存中都设置为“共享”。

答案 2 :(得分:2)

在x86上,缓存保持一致性以确保不会出现这样的问题。

第一部分是每个缓存跟踪它所拥有的每一行的状态 1 。如果(使用你的例子)一个数据同时保存在两个缓存中,一个写入它,它会将其缓存行设置为“已修改”状态,并向另一个CPU发送信号告诉它将用于保存相同数据的缓存行设置为“无效”状态。

难题的第二部分是每个CPU“窥探”所有内存事务(通过其他CPU或通过总线主控PCI设备),以便当其他人试图读取其缓存中的数据时“看到”。当发生这种情况时,它会强制暂停该事务,将数据从其缓存写入内存,然后在数据写入后继续执行事务,以便获取当前数据。

  1. 类的状态集是Modified,Exclusive,Shared和Invalid(MESI)。大多数现代CPU至少增加一个状态(通常是“拥有”,给予MOESI),还有一些添加更多。实际上,所有这些都包括至少修改和无效。