Я читал подобные ответы на этом сайте и в других местах, но в некоторых случаях все еще запутался.C volatile, и проблемы с аппаратным кэшированием
Я знаю, что стандарт на самом деле гарантирует нам, я понимаю предполагаемое использование ключевого слова, и я хорошо знаю разницу между кэшированием компилятора и L1/L2/ect. кэширование; это больше для любопытства, я понимаю другие случаи.
Скажем, у меня есть переменная, объявленная volatile
в С. Четыре сценария:
- обработчики сигналов, однопоточный (Как и предполагалось): Это проблема ключевое слово должно было решить. Мой процесс получает обратный вызов сигнала от ОС, и я изменяю переменную
volatile
из обычного выполнения моего процесса. Поскольку он был объявленvolatile
, нормальный процесс не сохранит это значение в регистре CPU и всегда будет выполнять загрузку из памяти. Даже если обработчик сигнала записывает в переменнуюvolatile
, так как обработчик сигнала имеет то же адресное пространство, что и обычный процесс, даже если переменнаяvolatile
была предварительно кэширована в аппаратном обеспечении (т.е. L1, L2), мы гарантируем, что основной процесс будет загрузите правильную обновленную переменную. Отлично, все счастливы. - DMA-передачи, однопоточные: Говорят, что переменная
volatile
отображается в область памяти, для которой происходит запись DMA. Как и раньше, компилятор не будет хранить переменнуюvolatile
в регистре CPU и всегда будет выполнять загрузку из памяти; однако, если эта переменная существует в аппаратном обеспечении кеш, тогда запрос на загрузку никогда не достигнет основной памяти. Если контроллер DMA обновляет MM за спиной, мы никогда не получим обновленное значение. В упреждающей ОС нас спасает тот факт, что в конечном итоге мы, вероятно, будем отключать контекст, и в следующий раз, когда наш процесс возобновится, кеш будет холодным, и нам действительно придется перезагружать из основной памяти - так что мы получим правильную функциональность. В конечном итоге (наш собственный процесс также может поменять эту строку кэша), но опять же, мы можем потратить ценные циклы, прежде чем это произойдет). Существует ли стандартизованная поддержка HW или поддержка ОС, которая уведомляет аппаратные кэши, когда основная память обновляется через контроллер DMA? Или нам нужно явно очистить кеш, чтобы гарантировать, что мы не читаем ложное значение? (Это возможно даже в архитектур в списке?) - отображенные в память регистры, однопоточный: То же, # 2, за исключением того, переменная
volatile
отображается в отображаемой памяти регистра (или явного ввода-вывода порта) , Я бы предположил, что это более сложная проблема, чем № 3, поскольку, по крайней мере, контроллер DMA будет сигнализировать CPU, когда он будет передан, что дает OS или HW возможность что-то сделать. - Mutilthreaded: Если у меня есть переменная
volatile
, существует ли какая-либо гарантия согласованности кеша между несколькими потоками, работающими на отдельных физических ядрах? Как и вправду, компилятор все еще выдаёт инструкции загрузки из памяти, но если значение кэшируется в кеше одного ядра, есть ли какая-либо гарантия того же значения в кэшах другого ядра? (Я бы предположил, что это не проблема для гиперпотоков потоков на разных логических ядрах на одном физическом ядре, поскольку они разделяют физическую кэш-память). Моя подавляющая интуиция говорит «нет», но я подумал, что перечислил случай здесь.
Если возможно, проведите различие между архитектурами x64 и ARMv6/7/8, а также решениями ядра и пользователя.
c/C++ 'volatile' не имеет ничего общего с оборудованием. Он просто отмечает переменную для компилятора. Компилятор не изменяет порядок доступа к отмеченным переменным и не оптимизирует доступ к ним. –
@MichaelNastenko Мне показалось, что я знаю это. Может быть, я должен был понять, что я смотрю, есть ли доступная поддержка ОС/архитектуры, которая * могла бы быть использована компилятором за пределами стандарта C –
'volatile' означает« без переупорядочения, без оптимизации ». Не больше, не меньше. # 1- # 3 сценарии, которые вы упомянули, решены аппаратными средствами. # 4 обычно решается MESI или любым другим протоколом когерентности кэша, а c/C++ 'volatile' бесполезен в этом случае. –