Атомарная (греч. άτομος — неделимое) операция — операция, которая либо выполняется целиком, либо не выполняется вовсе; операция, которая не может быть частично выполнена и частично не выполнена.
В данной статье описываются простейшие атомарные операции (чтение, запись и т. п.), хотя термин может относиться к более высокоуровневым операциям, таким как, например, серия запросов к СУБД в рамках одной транзакции.
Атомарные операции используются в многопроцессорных компьютерах и в многозадачных операционных системах для обеспечения доступа нескольких процессов и/или нескольких потоков одного процесса к разделяемым между ними ресурсам. Атомарная операция выполняется только одним потоком.
Атомарность операций может обеспечиваться аппаратно (аппаратурой) и программно (программным кодом). В первом случае используются особые машинные инструкции, атомарность выполнения которых гарантируется аппаратурой. Во втором случае используются специальные программные средства синхронизации, с помощью которых осуществляется блокировка разделяемого ресурса; после блокировки выполняется операция, которую требуется выполнить атомарно. Блокировка представляет собой атомарную операцию, которая либо предоставляет ресурс в пользование потоку, либо сообщает потоку о том, что ресурс уже используется другим потоком или процессом (занят).
В разделе не хватает ссылок на источники (см. рекомендации по поиску). |
Машинные инструкции, выполнение которых всегда можно считать атомарным:
Машинные инструкции, которые не являются атомарными:
Атомарные инструкции процессоров архитектуры x86:
Кроме того, многие машинные инструкции вида «чтение-модификация-запись» выполняются атомарно при наличии префикса LOCK[4] (опкод 0xF0), например, следующие:
Префикс LOCK вызывает блокировку доступа к памяти на время выполнения инструкции. Блокировка может распространяться на область памяти шире, чем длина операнда, например, на длину линии кэша.
Особенностью процессоров архитектур RISC является отсутствие инструкций вида «чтение-модификация-запись». В процессорах RISC с архитектурами DEC Alpha, PowerPC, MIPS и ARM (ARMv6 и старше) поддерживается механизм неблокирующего эксклюзивного доступа к памяти. Атомарные операции реализуются с использованием пары инструкций эксклюзивного чтения-записи LL и SC следующим образом:
Первая инструкция (LL) загружает данные из ячейки памяти в регистр и помечает ячейку, как ячейку для эксклюзивного доступа. Далее производятся необходимые изменения данных в регистре. Запись данных из регистра в память (SC) производится только в том случае, если значение ячейки памяти не менялось. Если значение менялось, три операции (LL, изменение данных и SC) следует повторить.
Компиляторы языков высокого уровня, как правило, не используют при генерации кода атомарные инструкции, поскольку, во-первых, атомарные операции во много раз более ресурсоёмкие, чем обычные, а во-вторых, у компилятора нет информации о том, когда доступ к данным должен осуществляться атомарно (так как даже модификатор volatile для переменной в языках C/C++ не означает реальной необходимости применения атомарных операций). В случае необходимости программист может использовать атомарные инструкции одним из следующих способов: