OSDev Wiki
Advertisement

Синхронизация доступа к памяти необходима в многопроцессорных системах для организации взаимодействия между программами, выполняемыми на разных процессорах.

В версиях, предшествующих ARMv6, единственным средством синхронизации являются команды SWP и SWPB, выполняющие обмен содержимым между регистром общего назначения и ячейкой памяти, причём на всё время выполнения операции доступ к памяти блокируется. Эти команды позволяют реализовать простейшие семафоры типа «занят/свободен», однако более сложные средства синхронизации реализовать не так просто.

В версии ARMv6 инструкции SWP и SWPB объявлены устаревшими. Они по-прежнему поддерживаются для обеспечения совместимости, однако в разрабатываемых приложениях следует использовать новые команды монопольной загрузки и записи LDREX и STREX, позволяющие между монопольной загрузкой и записью значения производить промежуточные вычисления.

Функционирование команд LDREX и STREX обеспечивается наличием у каждого процессора специального узла — монитора адресов (address monitor), который следит за всеми выполняющимися доступами к памяти и при необходимости управляет ими. Мониторы разных процессоров связаны между собой, что и позволяет им осуществлять блокировку доступа к определённым ячейкам памяти. Следует заметить, что конкретные детали функционирования и даже точное местоположение мониторов (например, мониторы могут быть «размазаны» между собственно процессорами и модулями памяти) спецификация ARM не оговаривает, оставляя все тонкости реализации разработчикам процессоров.

Монитор каждого процессора логически представляет собой машину состояний, имеющую два состояния: «открытый доступ» и «монопольный доступ». В состоянии «монопольный доступ» монитор хранит сведения о том, к какой области памяти осуществляется монопольный доступ. В зависимости от реализации может блокироваться область размером от 4 до 128 байтов, для чего монитор сохраняет старшие 25—30 разрядов адреса области; младшие разряды считаются равными нулю. Монитор различает доступы к неразделяемой и разделяемой памяти (последняя отличается наличием атрибута «разделяемая»).

Монопольный доступ к неразделяемой памяти

Команда LDREX, выполненная процессором при состоянии его локального монитора «открытый доступ» и адресованная памяти, не имеющей атрибута «разделяемая», считывает значение по заданному в ней адресу и переводит монитор в состояние «монопольный доступ». Последующие команды LDREX оставляют монитор в состоянии «монопольный доступ», но модифицируют сохранённый адрес блокированной области.

Команда STREX, выполняемая в состоянии «открытый доступ», не модифицирует адресуемые ячейки памяти и завершается с кодом 1, заносимым в указанный в ней регистр, что свидетельствует о её неудачном выполнении. В состоянии «монопольный доступ» и с адресом, принадлежащим блокированной области, она переводит монитор в состояние «открытый доступ», выполняет запись в память и завершается с кодом 0 (успешное выполнение). Если же адрес, заданный в этой команде, не принадлежит блокированной области, монитор всё равно переходит в состояние «открытый доступ», однако завершится ли команда успехом (запись в память и возврат кода 0) либо неудачей (возврат кода 1 без записи в память), зависит от реализации.

Команды обычной записи, адресованные незаблокированной области, всегда выполняются обычным образом. Команды, попадающие в блокированную область, либо просто выполняют запись,, либо выполняют запись и снимают статус блокировки, переводя монитор в состояние «открытый доступ» — это зависит от особенностей реализации процессора.

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

Монопольный доступ к разделяемой памяти

Доступы к регионам памяти, имеющим атрибут «разделяемая», контролируются так называемым глобальным монитором. Реализуемая им для каждого конкретного процессора машина состояний отслеживает все обращения к памяти со стороны этого процессора независимо от того, относятся они к разделяемым или неразделяемым областям, а также все обращения к разделяемым регионам памяти со стороны прочих процессоров (и других активных устройств, способных самостоятельно осуществлять прямой доступ к памяти; для простоты о таких устройствах далее специально говориться не будет). Технически глобальный монитор может быть реализован в виде связки локальных мониторов входящих в вычислительную систему процессоров или некая внешняя схема — все детали реализации оставлены на откуп разработчикам конкретных моделей процессоров.

Команда LDREX, выполненная процессором при состоянии связанной с ним машины состояний «открытый доступ», считывает значение по заданному адресу и переводит машину в состояние «монопольный доступ». Последующие команды LDREX, выданные этим же процессором, оставляют машину в состоянии «монопольный доступ», но модифицируют сохранённый адрес блокированной области.

Команда LDREX, выполняемая одним процессором, не влияет на машину состояний, связанную с другим процессором.

Команда STREX, выполняемая в состоянии «открытый доступ», всегда завершается неудачей (не модифицирует адресуемые ячейки памяти и возвращает код 1). В состоянии «монопольный доступ» она гарантированно завершится успехом (выполнит запись в память и возвратит код 0) только в том случае, если заданный в ней адрес попадает в заблокированную область, при этом машина состояния, соответствующая данному процессору, перейдёт в состояние «открытый доступ». Если адрес, указанный в команде, не соответствует заблокированной области, команда STREX может закончиться как успехом, так и неудачей — это определяется реализацией. Переход машины в состояние «открытый доступ» в этом случае также определяется реализацией, причём он никак не связан с успешностью записи в память: команда, адресованная не тому региону, который заблокирован, может успешно выполнить запись в память и вернуть код 0, но оставить монитор в состоянии «монопольныйй доступ», равно как и команда, завершившаяся неудачей, может перевести его в состояние «открытый доступ».

Команда STREX, выполняемая другим процессором и адресованная той же области памяти, что заблокирована данным процессором, переведёт машину состояний данного процессора в состояние «открытый доступ» только в том случае, если она завершится успешно, т.е. реально выполнит запись в память (что может случиться только в случае, если этот регион блокирован и на процессоре, выполняющем эту команду). Если запись выполнена не была, состояние машины данного процессора не меняется. Команда STREX, выполняемая другим процессором и обращённая к региону, который не блокирован данным процессором, не влияет на его машину состояний.

Обычные команды записи в память, адресованные не той области памяти, которая блокирована данным процессором, не оказывают влияния на его машину состояния независимо от того, какой процессор выполняет эти команды. Команды обычной записи в память, выполняемые другим процессором и адресованные заблокированной данным процессором области, переведут его машину в состояние «открытый доступ». Обычные команды записи, обращающиеся к блокированной области данного процессора, переведут его машину состояния в состояние «открытый доступ», если они выполняются другим процессором. Если же они выполняются этим же процессором, машина состояний может перейти в состояние «открытый доступ» или остаться в состоянии «монопольный доступ» — это определяется реализацией.

Ограничения

1. В каждый момент времени процессор может блокировать лишь одну область памяти.

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

3. Поскольку команды обычной записи могут вызвать снятие состояния блокировки, использовать их между LDREX и STREX не следует.

4. Нежелательно также выполнять команды выборки из памяти или какие-либо операции с кэшем, поскольку в некоторых реализациях они могут привести к снятию состояния блокировки.

5. Отказы данных влияют на состояние блокировки непредсказуемым образом, поэтому рекомендуется в обработчик этих исключений вставлять «пустую» инструкцию STREX, которая снимет блокировку (однако не гарантируется,что она снимет блокировку разделяемой области).

6. Для повышения производительности рекомендуется разносить объекты, к которым может осуществляться монопольный доступ, на расстояние не менее 128 байтов, поскольку максимальный размер блокируемой области равен этой величине.

Advertisement