Почему нужно использовать общий барьер для гарантии транзитивности процессора?

Недавно я прочитал транзитивность процессора в барьерах памяти, и автор подчеркивает, что только общий барьер может гарантировать транзитивность. Но я не очень хорошо понимаю это. Например:

CPU 1                      CPU 2                      CPU 3
=======================    =======================    =======================
{ X = 0, Y = 0 }
STORE X=1                  LOAD X                     STORE Y=1
                           <read barrier>             <general barrier>
                           LOAD Y                     LOAD X

Предположим, что X в кеше CPU3, и статус изменен, Y в кеше CPU2, и статус также изменен.

CPU1 разделяет свой буфер хранения с CPU2, если мы добавим барьер записи перед барьером чтения. (это становится общим барьером)

1) CPU1 устанавливает значение X(X=1) в буфере хранения.

2) CPU2 считывает значение X из буфера хранилища (буфер общего хранилища).

3) CPU2 помечает X в буфере хранения (барьер записи) и читает очередь недействительных, чтобы гарантировать, что сообщения от CPU3(барьер чтения) не будут аннулированы.

4) CPU2 хочет изменить строку кэша X с недействительной на измененную, поэтому отправляет сообщения о недействительности в CPU3.

5) CPU3 получает недействительные сообщения X, помещает их в очередь аннулирования и отвечает на CPU2.

6) CPU2 получает ответ, затем записывает X = 1 в память или кэш и загружает Y == 0.

...

7) CPU3 обнаружит, что имеет недействительное сообщение X в своей недействительной очереди, когда он выполняет общий барьер, после этого X должно быть равно 1.

Все в порядке, я могу понять. Однако я прочитал другой пример из рисунка 14.3 perbook, как показано ниже:

thread0(void) {
    A = 1;
    smp_wb();
    B = 1;
}
thread1(void) {
    while (B == 0)
        continue;
    barrier();
    C = 1;
}
thread2(void) {
    while (C == 0)
        continue;
    barrier();
    assert(A == 1);
}

Есть несколько возможностей отстаивать огонь. Автор сказал, что изменить все барьеры на smp_mb можно исправить в ответе на Quick Quiz 14.2.

Итак, мой вопрос: зачем нам менять барьер в thread1 на smp_mb? Если thread0 и thread1 работают на CPU0 и CPU1, и они совместно используют буфер хранилища. Их буфер хранения будет как bleow после того, как thread1 выполнит Store C = 1.

[A (wb), B, C]

Поскольку thread2(работает на CPU2) также использует smp_mb вместо барьера, поэтому он гарантирует, что A должно быть 1, если он видит C == 1.

Я описываю все вышеперечисленное в протоколе согласованности памяти MESI. Может быть, автор подразумевает, что существуют другие протоколы, которые должны создавать барьер в thread1 вместо smp_mb, чтобы гарантировать транзитивность процессора?

Кто-нибудь может дать мне пример, пожалуйста?

Может быть, это ошибка думать о транзитивности в конкретном протоколе. Мы должны помнить, что rmb() или wmb() не могут гарантировать транзитивность процессора, потому что существует очень много разных протоколов и архитектур.

0 ответов

Другие вопросы по тегам