Ответ 1
Самый простой ответ: вы должны использовать один из трех заграждений (LFENCE
, SFENCE
, MFENCE
) для обеспечения одной из 6 данных. Согласованность:
- Расслабление
- Потребляйте
- Приобретать
- Release
- Приобретать-релиз
- Последовательная
С++ 11:
Первоначально вы должны рассмотреть эту проблему с точки зрения степени порядка доступа к памяти, которая хорошо документирована и стандартизирована на С++ 11. Сначала вы должны прочитать: http://en.cppreference.com/w/cpp/atomic/memory_order
x86/x86_64:
1. Последовательность получения-освобождения:. Тогда важно понять, что в x86 для доступа к обычной ОЗУ (по умолчанию помечен как WB - Write Back и тот же эффект с WT (Write Throught) или UC (Uncacheable)) с помощью asm MOV
без каких-либо дополнительных команд автоматически обеспечивает порядок памяти для согласования с принятием-освобождением - std::memory_order_acq_rel
.
То есть для этой памяти имеет смысл использовать только std::memory_order_seq_cst
только для обеспечения последовательной согласованности. Т.е. когда вы используете: std::memory_order_relaxed
или std::memory_order_acq_rel
, тогда скомпилированный код ассемблера для std::atomic::store()
(или std::atomic::load()
) будет таким же - только MOV
без каких-либо L/S/MFENCE
.
Примечание. Но вы должны знать, что не только CPU, но и С++ - компилятор может переупорядочить операции с памятью, и все 6 барьеров памяти всегда влияют на компилятор С++ независимо от архитектуры ЦП.
Затем вы должны знать, как он может быть скомпилирован из С++ в ASM (собственный машинный код) или как вы можете записать его на ассемблере. Чтобы обеспечить любую последовательность, исключающую последовательность, вы можете просто написать MOV
, например MOV reg, [addr]
и MOV [addr], reg
и т.д.
2. Последовательная непротиворечивость: Но для обеспечения последовательной согласованности вы должны использовать неявные (LOCK
) или явные заграждения (L/S/ MFENCE
), как описано здесь: Почему GCC не использовать LOAD (без забора) и STORE + SFENCE для последовательной согласованности?
-
LOAD
(без забора) иSTORE
+MFENCE
-
LOAD
(без забора) иLOCK XCHG
-
MFENCE
+LOAD
иSTORE
(без забора) -
LOCK XADD
(0) иSTORE
(без забора)
Например, GCC использует 1, но MSVC использует 2. (Но вы должны знать, что MSVS2012 имеет ошибку: Требуется ли для семантики` std:: memory_order_acquire` процессорные инструкции на x86/x86_64?)
Затем вы можете прочитать Herb Sutter, вашу ссылку: https://onedrive.live.com/view.aspx?resid=4E86B0CF20EF15AD!24884&app=WordPdf&authkey=!AMtj_EflYn2507c
Исключение к правилу:
Это правило справедливо для доступа, используя MOV
для обычного ОЗУ, помеченного по умолчанию как WB - Write Back. Память помечена в Таблица страниц в каждом PTE (Таблица таблицы Enrty) для каждой страницы (непрерывная память 4 КБ).
Но есть некоторые исключения:
-
Если мы отмечаем память в Таблице страниц как Write Combined (
ioremap_wc()
в POSIX), то автоматически сохраняет только Consquency Consquency, и мы должны действовать как в следующем абзаце. -
См. ответ на мой вопрос: fooobar.com/info/160656/...
- Пиши в память не переупорядочиваются с другими записями, с следующими исключениями:
- записи выполняются с помощью команды CLFLUSH;
- потоковые хранилища (записи), выполняемые с инструкциями невременного перемещения (MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS и MOVNTPD); и
- строковые операции (см. раздел 8.2.4.1).
В обоих случаях 1 и 2 вы должны использовать дополнительную SFENCE
между двумя записями на один и тот же адрес, даже если вы хотите, чтобы Accquire-Release Consistency, потому что здесь automaticaly обеспечивает только Согласование согласования, и вы должны сделать Release (SFENCE
) самостоятельно.
Отвечайте на два вопроса:
Иногда при выполнении хранилища ЦП будет записывать в свой буфер хранилища вместо кеша L1. Я, однако, не понимаю который CPU сделает это?
С точки зрения пользователя кеш L1 и Store Buffer действуют по-разному. L1 быстро, но Store-Buffer быстрее.
-
Store-Buffer - это простая очередь, в которой хранятся только Writes и которые не могут быть переупорядочены - это делается для увеличения производительности и скрыть задержку доступа к кешу (L1 - 1ns, L2 - 3ns, L3 - 10ns) (CPU-Core полагает, что запись хранится в кеше и выполняет следующую команду, но в то же время ваши записи будут сохранены только в Store-Buffer и будут сохранены в кеше L1/2/3 позже), то есть CPU -Core не нужно ждать, когда Writes будет сохранен в кеше.
-
Кэш L1/2/3 - выглядит как прозрачный ассоциированный массив (адрес - значение). Он быстрый, но не самый быстрый, потому что x86 автоматически обеспечивает согласованность приема и освобождения, используя кеш-когерентный протокол MESIF/MOESI. Это делается для более простого многопоточного программирования, но снижает производительность. (Поистине, мы можем использовать алгоритмы Write Contentions Free и структуры данных, не используя когерентный кеш, т.е. Без MESIF/MOESI, например, над PCI Express). Протоколы MESIF/MOESI работает над QPI, который соединяет ядра в процессорах и ядрах между различными процессорами в многопроцессорных системах (ccNUMA).
CPU2 может захотеть загрузить значение, которое было записано в CPU1 буфер хранения. Насколько я понимаю, проблема в том, что CPU2 не видит новое значение в буфере хранения CPU1.
Да.
Почему протокол MESI не может включают буферы хранения промывки в рамках своего протокола.
Протокол MESI не может включать только буферизацию буфера хранения как часть его протокола, потому что:
- Протоколы MESI/MOESI/MESIF не связаны с Store-Buffer и не знают об этом.
- Автоматическая очистка Хранителя буфера при каждом использовании Writes уменьшит производительность - и сделает его бесполезным.
- Ручная очистка Храните буфер на всех удаленных ЦП-ядрах (мы не знаем, на каком буфере хранения ядра содержится требуемая запись), используя некоторую команду, - снизит производительность (в 8-х процессорах x 15 Cores = 120 ядер при том же time flush Store-Buffer - это ужасно)
Но ручная очистка Храните буфер на текущем CPU-Core - да, вы можете сделать это, выполнив команду SFENCE
. Вы можете использовать SFENCE
в двух случаях:
- Обеспечить последовательную согласованность оперативной памяти с кэшем кэша записи
- Чтобы обеспечить согласованность получения и выпуска в исключениях правила: ОЗУ с записью Комбинированное кеширование, для операций записи, выполняемых с помощью команды CLFLUSH, и для команд Non-Temporal SSE/AVX
Примечание:
Нужно ли нам LFENCE
в любом случае на x86/x86_64? - вопрос не всегда ясен: Есть ли смысл в LFENCE в процессорах x86/x86_64?
Другая платформа:
Затем вы можете читать, как в теории (для сферического процессора в вакууме) с помощью Store-Buffer и Invalidate-Queue, ваша ссылка: http://www.puppetmastertrading.com/images/hwViewForSwHackers.pdf
И как вы можете обеспечить последовательную согласованность на других платформах, не только с L/S/MFENCE и LOCK, но и с LL/SC: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html