Если операция записи происходит во время монопольного доступа к кешу, почему происходит гонка данных? - PullRequest
0 голосов
/ 29 апреля 2019

Я читал о протоколе 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);

сказано, что общий результат состоит в том, что переменная увеличивается только один раз, в то время как оба ядра пытаются увеличить ее (результат, как ожидается, будет равен двум). Таким образом, вопрос заключается в том, что если во время операции записи оба ядра запрашивают монопольный доступ к строке кэша (и, следовательно, другие ядра «ждут» своей очереди на изменение и, следовательно, получают также монопольный доступ), почему происходит скачок данных в этой переменной?

1 Ответ

4 голосов
/ 29 апреля 2019

Если я правильно прочитал вопрос, MESI - это просто красная сельдь здесь:

0   reg = load(&counter);   

counter теперь загружено в регистр процессора.

1   reg = reg + 1;                reg = load(&counter);

Первый процессор увеличил значение, второй загрузил старый.

2   store(&counter, reg);         reg = reg + 1;

Первый процессор хранит значение, второй увеличивает его устаревшее.

3                                 store(&counter, reg);

Второй процессор хранит результат расчета на основе устаревшего значения.

Пока ясно. Теперь, как это изменится, если добавить MESI-состояния:

0   reg = load(&counter);   

counter находится в кэше ЦП 1, помечено E.

1   reg = reg + 1;                reg = load(&counter);

counter все еще находится в кэше ЦП 1, но также загружается в кэш ЦП 2. Таким образом, обе строки кэша должны быть отмечены как S

2   store(&counter, reg);         reg = reg + 1;

Теперь counter сохраняется обратно в кеш. Таким образом, кэш ЦП 1 должен быть помечен как M, а кэш ЦП 2 признан недействительным (помечен как I).

3                                 store(&counter, reg);

Поскольку кэш ЦП 2 признан недействительным, его необходимо обновить, прежде чем может произойти операция store, что, в свою очередь, требует, чтобы кэш ЦП 1 был записан обратно в память до (конечно).

Но все, что делается сейчас, значение в reg по-прежнему рассчитывалось на основе устаревшего значения и все равно перезаписывает (теперь обновленное) значение в кеше ...

Добавление окончательной детали: после операции кэш ЦП 2 будет помечен M, а кэш ЦП 1 I.

...