Определяя более строго, семафор — это специальная переменная, для которой разрешены только две операции, формально именуемые ожиданием или приостановкой (wait) и оповещением (signal). Поскольку в программировании Linux у приостановки и оповещения уже есть специальные значения, мы будем применять оригинальное обозначение:

□ P(переменная-семафор) для приостановки (wait);

□ V(переменная-семафор) для оповещения (signal).

Эти буквы взяты из голландских слов для приостановки (passeren — проходить, пропускать как в случае контрольной точки перед критической секцией) и для оповещения (vrijgeven — предоставлять или освобождать, как в случае отказа от контроля критической секции). Вы можете встретить термины "вверх" (up) и "вниз" (down), применяемые в отношении семафоров по аналогии с использованием сигнальных флажков.

<p>Описание семафора</p>

Простейший семафор — это переменная, способная принимать только значения 0 и 1, бинарный или двоичный семафор. Это наиболее распространенный вид семафора. Семафоры, принимающие много положительных значений, называют семафорами общего вида. В оставшейся части главы мы сосредоточимся на двоичных семафорах.

Определения операций P и V удивительно просты. Предположим, что у вас есть переменная-семафор sv. В этом случае обе операции определяются так, как представлено в табл. 14.1.

Таблица 14.1

ОперацияОписание
Р(sv)Если sv больше нуля, она уменьшается на единицу. Если sv равна 0, выполнение данного процесса приостанавливается
V(sv)Если какой-то другой процесс был приостановлен в ожидании семафора sv, переменная заставляет его возобновить выполнение. Если ни один процесс не приостановлен в ожидании семафора sv, значение переменной увеличивается на единицу

Другой способ описания семафора — считать, что переменная sv, равная true, когда доступна критическая секция, уменьшается на единицу с помощью P(sv) и становится равна false, когда критическая секция занята, и увеличивается на единицу операцией V(sv), когда критическая секция снова доступна. Имейте в виду, что обычная переменная, которую вы уменьшаете и увеличиваете на единицу, не годится, т.к. в языках С, С++, C# или практически в любом традиционном языке программирования у вас нет возможности сформировать единую атомарную операцию, проверяющую, равна ли переменная true, и если это так, изменяющую ее значение на false. Именно эта функциональная возможность делает операции с семафором особенными.

<p>Теоретический пример</p>

С помощью простого теоретического примера можно посмотреть, как действует семафор. Предположим, что у вас есть два процесса: proc1 и proc2, оба нуждающиеся в некоторый момент выполнения в монопольном доступе к базе данных. Вы определяете один бинарный семафор sv, который стартует со значением 1 и доступен обоим процессам. Далее обоим процессам нужно выполнить одну и ту же обработку для доступа к критической секции программного кода; эти два процесса могут быть двумя разными выполняющимися экземплярами одной и той же программы.

Оба процесса совместно используют переменную-семафор sv. Как только один процесс выполнил операцию P(sv), он получил семафор и может войти в критическую секцию программы. Второму процессу вход в критическую секцию запрещен, т.к., когда он попытается выполнить операцию P(sv), он вынужден будет ждать до тех пор, пока первый процесс не покинет критическую секцию и не выполнит операцию V(sv), освобождающую семафор.

Требуемый псевдокод у обоих процессов идентичен:

semaphore sv = 1;

loop forever {

 P(sv);

 critical code section;

 V(sv);

 noncritical code section;

}

Код на удивление прост, потому что определение операций P и V наделяет их большими функциональными возможностями.

Рис. 14.1 

На рис. 14.1 показана схема действующих операций P и V, напоминающих ворота в критических секциях программного кода.

<p>Реализация семафоров в Linux</p>
Перейти на страницу:

Похожие книги