示例代码:
1
internal
sealed
class
CacheCoherencyProblem
2
{
3
private Byte m_initialized = 0;
4
private Int32 m_value = 0;
5
6
public void Thread1()
7
{
8
m_value = 5;
9
m_initialized = 1;
10
}
11
12
public void Thread2()
13
{
14
if (m_initialized == 1)
15
{
16
Console.Write(m_value);
17
}
18
}
19
}
在多CPU或多内核CPU机器中,因CPU高速缓存机制,而产生内存不一致现象
假设在一个多CPU的机器上创建了该实例:
CPU1执行Thread1方法,CPU2执行Thread2方法,假定程序的执行顺序为:
1.CPU1的线程在读取某个字节时,m_value字段的字节刚好位于这个字节之前,
根据CPU高速缓存机制,m_value被预读到CPU高速缓存中(因为应用程序通常
读取的字节在内存中彼此互邻,这样可以提升性能)
2.CPU1执行Thread1,将m_value改为5,但根据CPU高速缓存机制,改变仅暂时
存在于CPU1的高速缓存中,直到某个时间才会刷新到内存中。我们这里假设
此步操作可能需要经过很久才会反映到内存中
3.CPU1继续执行Thread1方法,同样在自己的高速缓存中,修改了m_initialized
的值为1。但这次的m_initialized却处在CPU1高速缓存的不同区段,结果
是很快被刷新到内存中了。
4.CPU2开始执行Thread2方法,当访问m_initialized值时,CPU2会因高速缓存中
不存在m_initialized而去读取内存,结果是CPU2读取到m_initialized=1,随即
进入了if语句块。
5.CPU2继续执行Thread2方法,此时CPU2同样也会因高速缓存中不存在m_value而
去内存中取值,
但因为CPU1还没有将自己的m_value=5更新到内存,所以CPU2取到
了m_value=0
内存一致性
write back会涉及内存一致性,涉有到一系列的问题:
1)多处理要系统更新cache时,一个处理器修改了cache的内容,第二个处理器将不能访问这个cache,直到这个cache的内容被写内存.
在现代处理器中硬件已经做了精心的设计,确保这种事情不会发生,硬件负责保持cache在各个CPU之间一致.
2)外围硬件设备可以通过DMA(Direct Memory Access)访问内存,而不让处理器知道,也不会利用cache,这样在内存和cache之间就会出现不同步的情况.
管理DMA的操作是操作系统的工作,比如设备驱动程序,它将保证内存与cache的一致性.
3)当在cache中的数据比内存中的数据老时,称为stale.如果软件初始化DMA,使设备和RAM之间传递数据,那么软件必须告诉 CPU,cache中的条目必须失效.
4)当在cache中的数据比内存中的数据新时,称为dirty.在设备驱动程序允许一个设备经DMA从内存读数据时,它必须确保所有的dirty 条目写进内存.也叫做flushing或sync cache.