sho*_*dze 3 cpu x86-64 atomic instructions mesi
我正在阅读有关 MESI 协议的内容,并且无法理解如果我们对每个写入操作都具有独占访问权限,为什么会出现数据竞争,从而导致其他核心缓存中的缓存行无效?在这个例子中:
CYCLE # CORE 1 CORE 2
0 reg = load(&counter);
1 reg = reg + 1; reg = load(&counter);
2 store(&counter, reg); reg = reg + 1;
3 store(&counter, reg);
Run Code Online (Sandbox Code Playgroud)
据说总体结果是变量仅增加一次,而两个核心都尝试增加它(结果预计为两次)。所以问题是,如果在写入操作期间,两个内核都请求对缓存行的独占访问(因此其他内核“等待”轮到修改,从而也获得独占访问),为什么该变量上存在数据竞争?
如果我没看错的话,MESI 只是一个转移注意力的话题:
0 reg = load(&counter);
Run Code Online (Sandbox Code Playgroud)
counter现在已经被加载到CPU的寄存器中。
1 reg = reg + 1; reg = load(&counter);
Run Code Online (Sandbox Code Playgroud)
第一个处理器增加了值,第二个处理器加载了旧值。
2 store(&counter, reg); reg = reg + 1;
Run Code Online (Sandbox Code Playgroud)
第一个处理器存储值,第二个处理器增加其过时的值。
3 store(&counter, reg);
Run Code Online (Sandbox Code Playgroud)
第二处理器存储基于过时值的计算结果。
到目前为止应该很清楚了。现在,如果添加 MESI 状态,情况会如何改变:
0 reg = load(&counter);
Run Code Online (Sandbox Code Playgroud)
counter位于 CPU 1 缓存中,标记为E。
1 reg = reg + 1; reg = load(&counter);
Run Code Online (Sandbox Code Playgroud)
counter仍然驻留在 CPU 1 缓存中,但也会加载到 CPU 2 缓存中。所以两个缓存行都需要标记为S
2 store(&counter, reg); reg = reg + 1;
Run Code Online (Sandbox Code Playgroud)
现在counter被存储回缓存中。因此,CPU 1 缓存需要标记为M,而 CPU 2 缓存则失效(标记为I)。
3 store(&counter, reg);
Run Code Online (Sandbox Code Playgroud)
由于 CPU 2 缓存失效,因此需要在store操作发生之前对其进行更新,这反过来又要求 CPU 1 缓存之前写回内存(当然)。
但现在所做的一切,reg仍然是根据过时的值计算的,并且仍然覆盖缓存中的(现已更新的)值......
添加最后一个细节:操作完成后,CPU 2 缓存将被标记M为 CPU 1 缓存I。