Заборы памяти - нужна помощь, чтобы понять
Я читаю "Барьеры памяти" Пола МакКенни http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.07.23a.pdf Все объясняется очень подробно, и когда я вижу, что все ясно Я сталкиваюсь с одним предложением, которое сводит на нет все и заставляет меня думать, что я ничего не понял. Позвольте мне показать пример
void foo(void)
{
a = 1; #1
b = 1; #2
}
void bar(void)
{
while (b == 0) continue; #3
assert(a == 1); #4
}
скажем, эти две функции работают на разных процессорах. Теперь то, что могло бы произойти, это то, что сохранение в #1 можно увидеть после сохранения в b #2 вторым процессором, потому что очереди первого процессора сохраняются в "a" и переходят к сохранению инструкции b. Хорошо, это нормально, мы добавляем забор записи в строке между #1 и #2, но этот код все еще может завершиться ошибкой, потому что второй процессор может поставить в очередь сообщение о недействительности, поэтому мы добавляем еще один забор памяти (на этот раз читаем забор) в линия между № 4 и № 4.
void foo(void)
{
a = 1; #1
write_memory_barrier();
b = 1; #2
}
void bar(void)
{
while (b == 0) continue; #3
read_memory_barrier();
assert(a == 1); #4
}
это заставляет второй процессор обрабатывать все поставленные в очередь сообщения (сделать недействительными a) и снова прочитать его, отправив сообщение чтения MESI первому процессору на #4. ХОРОШО. Далее в статье говорится
Поэтому многие архитектуры ЦП предоставляют более слабые инструкции по защите памяти, которые выполняют только одну или другую из этих двух. Грубо говоря, "барьер чтения памяти" отмечает только недействительную очередь, а "барьер чтения памяти" отмечает только буфер хранилища. в то время как полноценный барьер памяти делает и то, и другое.
Отлично, понятно, но после этого вижу
Эффект этого состоит в том, что порядок барьера чтения памяти загружается только на процессор, который его выполняет, так что все нагрузки, предшествующие барьеру чтения памяти, будут завершены до любой нагрузки, следующей за барьером чтения памяти. Точно так же, порядок барьеров памяти записи сохраняется только снова, снова в ЦПУ, который его выполняет, и снова, так что все хранилища, предшествующие барьеру памяти записи, будут казаться завершенными до любого хранилища, следующего за барьером памяти записи.
так
все нагрузки, предшествующие барьеру чтения памяти, будут завершены до любой нагрузки, следующей за барьером чтения памяти
это смешивает все, что было объяснено ранее. Что это значит? Какую нагрузку в функции "bar" нужно выполнить до загрузки "a" #4? Я понимаю, что утверждение может потерпеть неудачу без барьера памяти в этой функции только потому, что процессор может прочитать старое значение, потому что ему все еще не удалось сделать недействительной свою строку кэша, где расположен объект "a".
Объяснение в деталях было бы очень полезно, я пытаюсь понять это весь день.
Большое спасибо заранее.
1 ответ
Что это значит?
Это означает, что если у вас есть:
read
read
read
READ BARRIER
read
read
read
тогда барьер чтения действует как "точка соединения", разделяющая эти чтения на две партии. Все чтения, предшествующие барьеру чтения, будут выполнены до начала любого чтения, следующего за барьером чтения.
Который загружает в bar()
должен завершиться до загрузки a
(#4) началось?
Все читает о b
(#3) вынуждены предшествовать любому прочтению a
(#4). Это означает, что a
не читается до b
больше не 0. Потому что foo()
использует барьер записи, чтобы гарантировать, что a
уже был изменен на 1
(#1) к тому времени, когда b
изменено (#2). Таким образом, два барьера работают вместе, чтобы гарантировать, что утверждение assert всегда будет успешным.