Атомарные операции. История вопроса

12 Ноя 2012

i8086, один из самых первых процессоров, выпускавшихся компанией Intel

Мультипроцессорная и, особенно, виртуализацонная платформа должны иметь гарантию того, что операции, которые при рассмотрении на аппаратном уровне состоят из нескольких шинных циклов, выполняются как неделимые. Такие операции называются атомарными (Atomic Operations).

Еще в i8086, одном из самых первых процессоров, выпускавшихся компанией Intel (советский аналог К1810ВМ86), машинные инструкции предусматривали использование префикса блокировки LOCK. Префикс размещался перед машинной командой, выполнение которой состоит из нескольких шинных циклов, и гарантировал запрет доступа к системной шине до завершения всех шинных циклов этой команды. Во время выполнения команды, защищенной префиксом блокировки, процессор формировал сигнал LOCK#, запрещающий арбитру шины (в те времена в этом качестве использовался контроллер i8289, аналог К1810ВБ89) передавать шину другому устройству.

Так, например, инструкция XCHG AL,DS:[BX] предназначена для обмена содержимого регистра AL и ячейки памяти по адресу DS:[BX]. Ее выполнение состоит из двух шинных циклов:

  1. Прочитать из памяти байт по адресу DS:[BX].
  2. Записать в память байт (значение AL) по адресу DS:[BX]

Если в мультипроцессорной системе ячейка памяти по адресу DS:[BX] используется как программный семафор для управления совместным доступом нескольких процессоров к некоторому ресурсу, возможна такая ситуация. Пусть значение DS:[BX]=0 означает, что доступ открыт, ресурс не используется, DS:[BX]=1 означает, что доступ закрыт, ресурс используется. Пусть в исходном состоянии DS:[BX]=0. Если первый процессор претендует на доступ к ресурсу, он должен выполнить команду XCHG AL,DS:[BX], для того, чтобы одной инструкцией опросить семафор (прочитать ячейку) и установить запрет доступа на время использования ресурса (записать в ячейку «единицу» из регистра AL).

Предположим, что и второй процессор также претендует на доступ к этому же ресурсу и делает то же самое.

Если второй процессор прочитает ячейку в тот момент, когда первый процессор уже прочитал оттуда 00h и увидел, что доступ открыт, но еще не записал туда 01h, для запрета доступа конкурентам, то получится, что оба процессора прочитали из семафора 00h. В результате оба программных потока получат равный доступ к общему ресурсу и начнут параллельное его использование, что неминуемо приведет к ошибке.

Если операция XCHG имеет статус Atomic и смена владельца шины невозможна между циклом чтения семафора и записью в него, проблем не будет. Второй процессор сможет прочитать семафор только после того, как первый запишет в него значение 01h, запрещающее доступ.

Отметим, что для команд, выполнение которых состоит из одного шинного цикла (одной записи или одного чтения), например MOV DS:[BX],AL или MOV AL,DS:[BX] такой проблемы нет, так как до завершения единственного шинного цикла смена владельца шины не возможна.

В однопроцессорных системах нарушение правила атомических операций не приведет к описанным последствиям, так как ячейка памяти не востребована другими устройствами в промежуточном (немодифицированном) состоянии. Не стоит волноваться по поводу распределения доступа к системным ресурсам и владельцам современных систем: сейчас процессоры автоматически выполняют инструкцию XCHG в атомическом режиме, даже если префикс LOCK не указан.