Модуль памяти (DIMM) может одновременно выполнять только одно: чтение или запись. Это продиктовано протоколом на периферийном разъеме DIMM; когда вы отправляете команду чтения или записи в модуль DIMM, он не может даже "услышать" другую команду, пока предыдущая команда не будет выполнена.
Все модули DIMM на общей шине памяти будут иметь одно ограничение за один раз. Но на многих платформах ПК имеется два или три канала памяти, и все ОЗУ на одном канале могут одновременно выполнять только одну операцию.
На машинах NUMA (с несколькими сокетами ЦП и "частной" памятью для каждого сокета) все это умножается на nCPU. то есть каждый процессор может обращаться к своей локальной памяти независимо от того, что другой процессор делает со своей памятью. Однако все процессоры все еще могут получить доступ ко всей оперативной памяти, это займет немного больше времени, если они должны пройти через другой процессор.
По сути, это зависит от кода приложений для реализации любых требований сериализации, которые они имеют для доступа к общим данным. Это делается с помощью операционной системы, которая предоставляет различные объекты и функции синхронизации для приложений. Эти объекты имеют такие имена, как семафоры (имя, заимствованное из сигнала железной дороги), мьютексы (сокращение от "взаимное исключение") и т.д. В зависимости от ОС они могут реализовывать по одному, n за один раз, семантика исключительной записи против общей записи и т. д. Эти функции обычно включают в себя "ожидание" или "блокирование": поток пытается, например, получить мьютекс, который по своей конструкции "защищает" совместно используемый ресурс. Если мьютекс уже принадлежит какому-либо другому потоку, то второй (и _n_th) запрашивающий поток блокируется, то есть ожидает и не возвращается из вызова получения, пока предыдущий владелец не освободит его.
Именно приложения должны использовать эти методы там, где это необходимо; операционная система не может требовать, например, чтобы вы имели собственный мьютекс перед доступом к данным, которые вы хотели защитить мьютексом. Это область разработки программ, которая может быть очень сложной как для правильной, так и для высокой производительности.
Подсистемы более высокого уровня, такие как базы данных, имеют встроенную кодировку для данных, которыми они управляют, и представляют программисту интерфейс, который "говорит" в терминах элементов базы данных, а не объектов синхронизации: программист будет вызывать функции для блокировки строки таблицы или отдельная ячейка, или набор строк, или, может быть, целая таблица, пока она выполняет обновления. Под ядром базы данных будут использоваться средства ОС, как описано ранее.
Внутренне операционная система обычно реализует эти функции синхронизации с помощью некоторой атомарной операции проверки и изменения, которая реализована в подсистеме памяти. Под "атомарным" я подразумеваю, что после начала операция гарантированно завершится до того, как любая другая атомарная операция может начаться в затронутой памяти. Примером, который обычно используется в Windows, является инструкция "взаимоблокировка сравнения и обмена". x86/x64 фактически предоставляют целый ряд таких инструкций, работающих с различными размерами данных.
Существуют методы, которые обеспечивают безопасный сериализованный доступ к совместно используемым данным без использования таких методов, но они работают только для нескольких особых случаев (например, "только один читатель и только один писатель") или для определенных типов данных.