如果在独占缓存访问期间发生写操作,为什么会出现数据竞争?
If write operation happens during exclusive cache access why is there data race?
我正在阅读有关 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);
据说总体结果是变量只递增一次,而两个内核都试图递增它(结果预计是两个)。所以问题是,如果在写入操作期间,两个内核都请求独占访问缓存行(因此其他内核 "wait" 轮到它们修改并因此也获得独占访问权限)为什么在该变量上存在数据竞争?
如果我没看错的话,MESI 只是一个转移注意力的东西:
0 reg = load(&counter);
counter
现已加载到 CPU 的寄存器中。
1 reg = reg + 1; reg = load(&counter);
第一个处理器递增该值,第二个处理器加载旧值。
2 store(&counter, reg); reg = reg + 1;
第一个处理器存储值,第二个处理器增加其过时的值。
3 store(&counter, reg);
第二个处理器存储基于过时值的计算结果。
到目前为止应该清楚了。现在如果添加 MESI 状态将如何改变:
0 reg = load(&counter);
counter
在 CPU 1 个缓存中,标记为 E
。
1 reg = reg + 1; reg = load(&counter);
counter
仍然驻留在 CPU 1 缓存中,但也被加载到 CPU 2 缓存中。所以两个缓存行都需要标记为S
2 store(&counter, reg); reg = reg + 1;
现在 counter
被存储回缓存中。 CPU 1 缓存因此需要标记为 M
,而 CPU 2 缓存失效(标记为 I
)。
3 store(&counter, reg);
由于 CPU 2 缓存失效,需要在 store
操作发生之前对其进行更新,这反过来又需要将 CPU 1 缓存写回之前的记忆(当然)。
但是现在所做的一切,reg
中的值仍然是根据过时的值计算的,并且仍然覆盖缓存中的(现在更新的)值...
添加最后一个细节:操作后,CPU 2 缓存将被标记为 M
和 CPU 1 缓存将被标记为 I
.
我正在阅读有关 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);
据说总体结果是变量只递增一次,而两个内核都试图递增它(结果预计是两个)。所以问题是,如果在写入操作期间,两个内核都请求独占访问缓存行(因此其他内核 "wait" 轮到它们修改并因此也获得独占访问权限)为什么在该变量上存在数据竞争?
如果我没看错的话,MESI 只是一个转移注意力的东西:
0 reg = load(&counter);
counter
现已加载到 CPU 的寄存器中。
1 reg = reg + 1; reg = load(&counter);
第一个处理器递增该值,第二个处理器加载旧值。
2 store(&counter, reg); reg = reg + 1;
第一个处理器存储值,第二个处理器增加其过时的值。
3 store(&counter, reg);
第二个处理器存储基于过时值的计算结果。
到目前为止应该清楚了。现在如果添加 MESI 状态将如何改变:
0 reg = load(&counter);
counter
在 CPU 1 个缓存中,标记为 E
。
1 reg = reg + 1; reg = load(&counter);
counter
仍然驻留在 CPU 1 缓存中,但也被加载到 CPU 2 缓存中。所以两个缓存行都需要标记为S
2 store(&counter, reg); reg = reg + 1;
现在 counter
被存储回缓存中。 CPU 1 缓存因此需要标记为 M
,而 CPU 2 缓存失效(标记为 I
)。
3 store(&counter, reg);
由于 CPU 2 缓存失效,需要在 store
操作发生之前对其进行更新,这反过来又需要将 CPU 1 缓存写回之前的记忆(当然)。
但是现在所做的一切,reg
中的值仍然是根据过时的值计算的,并且仍然覆盖缓存中的(现在更新的)值...
添加最后一个细节:操作后,CPU 2 缓存将被标记为 M
和 CPU 1 缓存将被标记为 I
.