Процессор (в частности, контроллер памяти) может использовать тот факт, что память не видоизменяется
Преимущество в том, что этот факт избавляет компилятор от использования мембранных инструкций при доступе к данным.
Барьер памяти, также известный как мембранная команда, команда ограничения памяти или команды ограничения, является типом команды барьера, которая заставляет центральный процессор (ЦП) или компилятор обеспечивать ограничение порядка операций памяти, выполняемых до и после команды барьера. Как правило, это означает, что определенные операции гарантированно выполняются до барьера, а другие - после.
Барьеры памяти необходимы, потому что большинство современных процессоров используют оптимизацию производительности, которая может привести к неправильному выполнению. Такое переупорядочение операций с памятью (загрузка и хранение) обычно проходит незамеченным в пределах одного потока выполнения, но может привести к непредсказуемому поведению в параллельных программах и драйверах устройств, если не будет тщательно контролироваться ...
Видите ли, когда к данным получают доступ из разных потоков, в многоядерном процессоре это происходит примерно так: разные потоки работают на разных ядрах, каждый из которых использует свой собственный (локальный для своего ядра) кэш - копию некоторого глобального кеша.
Если данные являются изменяемыми и программисту необходимо, чтобы они были согласованы между различными потоками, необходимо принять меры для обеспечения согласованности. Для программиста это означает использование конструкций синхронизации, когда они обращаются (например, читают) к данным в определенном потоке.
Для компилятора конструкция синхронизации в коде означает, что ему нужно вставить мембранную инструкцию , чтобы убедиться, что изменения, внесенные в копию данных на одном из ядер, правильно распространяются («публикуются»), чтобы гарантировать кэширование на других ядрах. иметь одну и ту же (актуальную) копию.
Несколько упрощенно смотрите примечание ниже , вот что происходит на многоядерных процессорах для мембран:
- Все ядра останавливают обработку - чтобы избежать случайной записи в кеш.
- Все обновления, сделанные для локальных кэшей, записываются обратно в глобальный - чтобы гарантировать, что глобальный кэш содержит самые последние данные. Это займет некоторое время.
- Обновленные данные записываются обратно из глобального кэша в локальные, чтобы гарантировать, что локальные кэши содержат самые последние данные. Это займет некоторое время.
- Все ядра возобновляют выполнение.
Видите ли, все ядра ничего не делают, пока данные копируются между глобальным и локальным кэшем . Это необходимо для обеспечения правильной синхронизации изменяемых данных (поточно-ориентированных). Если имеется 4 ядра, все 4 останавливаются и ждут, пока кешируются данные. Если их 8, все 8 останавливаются. Если их 16 ... ну, у вас есть 15 ядер, которые ничего не делают в ожидании того, что нужно сделать на одном из них.
Теперь давайте посмотрим, что происходит, когда данные неизменны? Независимо от того, какой поток обращается к нему, он гарантированно будет одинаковым. Для программиста это означает, что нет необходимости вставлять конструкции синхронизации, когда они обращаются (читают) к данным в определенном потоке.
Для компилятора это, в свою очередь, означает, что нет необходимости вставлять мембранную инструкцию .
В результате доступ к данным не должен останавливать ядра и ждать, пока данные будут записываться между глобальным и локальным кэшем. Это преимущество того факта, что память не видоизменяется .
Обратите внимание, что несколько упрощенное объяснение, приведенное выше, устраняет некоторые более сложные негативные последствия изменчивости данных, например, при конвейерной обработке . Чтобы гарантировать требуемое упорядочение, ЦПУ должен лишить законной силы коллекторы, затронутые изменениями данных - это еще одно снижение производительности. Если это реализуется путем простой (и, следовательно, надежной) отмены всех конвейеров, то отрицательный эффект еще более усиливается.