1

Я хотел бы понять на высоком уровне, как шина разделяемой памяти обрабатывает несколько одновременных операций чтения и записи общих данных из нескольких потоков, работающих на нескольких процессорах?

PS: мне не нужны кровавые подробности, потому что они, очевидно, будут зависеть от реализации. Мне просто нужен общий обзор того, что происходит за кулисами.

2 ответа2

1

"Шина" - это набор проводов между компонентами, а не сам компонент. Таким образом, проводка между процессором и его памятью называется шиной памяти; проводка к платам расширения - это шина PCI и т. д.

Возможно иметь несколько компонентов, управляющих шиной, хотя только один может управлять им одновременно, и его сигналы доставляются всем остальным компонентам на шине. Компонент, который контролирует доступ к шине, называется мастером шины. Может быть возможно изменить, какой компонент является мастером шины путем арбитража.

В многоядерной системе важна согласованность кэша. Поэтому, когда одно ядро выполняет запись в шину общей памяти, другие ядра будут отслеживать шину (проверять запись, даже если она идет из другого ядра в память). Если запись выполняется в место, кэшированное этим ядром, то ядро вытеснит или заменит свою запись в кэше. Таким образом, у него нет устаревшей информации.

1

Модуль памяти (DIMM) может одновременно выполнять только одно: чтение или запись. Это продиктовано протоколом на периферийном разъеме DIMM; когда вы отправляете команду чтения или записи в модуль DIMM, он не может даже "услышать" другую команду, пока предыдущая команда не будет выполнена.

Все модули DIMM на общей шине памяти будут иметь одно ограничение за один раз. Но на многих платформах ПК имеется два или три канала памяти, и все ОЗУ на одном канале могут одновременно выполнять только одну операцию.

На машинах NUMA (с несколькими сокетами ЦП и "частной" памятью для каждого сокета) все это умножается на nCPU. то есть каждый процессор может обращаться к своей локальной памяти независимо от того, что другой процессор делает со своей памятью. Однако все процессоры все еще могут получить доступ ко всей оперативной памяти, это займет немного больше времени, если они должны пройти через другой процессор.

По сути, это зависит от кода приложений для реализации любых требований сериализации, которые они имеют для доступа к общим данным. Это делается с помощью операционной системы, которая предоставляет различные объекты и функции синхронизации для приложений. Эти объекты имеют такие имена, как семафоры (имя, заимствованное из сигнала железной дороги), мьютексы (сокращение от "взаимное исключение") и т.д. В зависимости от ОС они могут реализовывать по одному, n за один раз, семантика исключительной записи против общей записи и т. д. Эти функции обычно включают в себя "ожидание" или "блокирование": поток пытается, например, получить мьютекс, который по своей конструкции "защищает" совместно используемый ресурс. Если мьютекс уже принадлежит какому-либо другому потоку, то второй (и _n_th) запрашивающий поток блокируется, то есть ожидает и не возвращается из вызова получения, пока предыдущий владелец не освободит его.

Именно приложения должны использовать эти методы там, где это необходимо; операционная система не может требовать, например, чтобы вы имели собственный мьютекс перед доступом к данным, которые вы хотели защитить мьютексом. Это область разработки программ, которая может быть очень сложной как для правильной, так и для высокой производительности.

Подсистемы более высокого уровня, такие как базы данных, имеют встроенную кодировку для данных, которыми они управляют, и представляют программисту интерфейс, который "говорит" в терминах элементов базы данных, а не объектов синхронизации: программист будет вызывать функции для блокировки строки таблицы или отдельная ячейка, или набор строк, или, может быть, целая таблица, пока она выполняет обновления. Под ядром базы данных будут использоваться средства ОС, как описано ранее.

Внутренне операционная система обычно реализует эти функции синхронизации с помощью некоторой атомарной операции проверки и изменения, которая реализована в подсистеме памяти. Под "атомарным" я подразумеваю, что после начала операция гарантированно завершится до того, как любая другая атомарная операция может начаться в затронутой памяти. Примером, который обычно используется в Windows, является инструкция "взаимоблокировка сравнения и обмена". x86/x64 фактически предоставляют целый ряд таких инструкций, работающих с различными размерами данных.

Существуют методы, которые обеспечивают безопасный сериализованный доступ к совместно используемым данным без использования таких методов, но они работают только для нескольких особых случаев (например, "только один читатель и только один писатель") или для определенных типов данных.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .