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

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

    Благодаря этому мы можем одновременно получить старое значение флаговой переменной и установить новое командой 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, чтобы сообщить об этом редактору.