Иллюстрированный самоучитель по теории операционных систем

Примитивы взаимоисключения

Благодаря этому мы можем одновременно получить старое значение флаговой переменной и установить новое командой xchg (eXCHanGe, обменять – операнды обмениваются значениями между собой – пример 7.3) – Если память модифицируется только одним процессором, исполняющим программу, префикс блокировки шины не нужен – зато, если процессоров (или других задатчиков шины) в системе несколько, префикс гарантирует взаимоисключение и для модификаций флага с их стороны.

Пример 7.3. Реализация примитива testandset через блокировку шины.

.globl flag
; 0 = False, 1 = True
flag:.db 0
proc process1
tryagain:
move eax, 1
lock xchg eax, flag
tst eax
bnz tryagain
критическая секция
; в данном случае о взаимоисключении можно не заботиться
xor eax, eax
move flag, eax
ret
endp

Другие процессоры, например VAX, предоставляют отдельные команды, исполняющиеся в режиме монопольного захвата шины. В частности, Именно так этот процессор исполняет команды вставки в очередь и исключения из нее.

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

Пример 7.4. Реализация взаимоисключения при помощи атомарной операции testandset (ЦИТ. ПО [Дейтел 1987]).

progam npimeptestandset
var активный: Boolean;
procedure процесс один;
var первому входить нельзя: Boolean;
begin
while true do
begin
первому входить нельзя: = True;
while первому входить нельзя do
testandset (первому входить нельзя, активный);
критический участок один;
активный: = False;
….
end
end;
procedure процесс два;
var второму входить нельзя: Boolean; begin
while true do
begin
второму входить нельзя: = True;
while второму входить нельзя do
testandset (второму входить нельзя, активный);
критический участок два;
активный: = False;
…..
end
end;

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

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.