Семафоры, мьютексы. Использование семафоров для синхронизации процессов
После того как поток выполнит все действия с данными D, значение переменной F(D) снова устанавливается равным 1.
Блокирующие переменные могут использоваться не только при доступе к разделяемым данным, но и при доступе к разделяемым ресурсам любого вида.
Если все потоки написаны с учетом вышеописанных соглашений, то взаимное исключение гарантируется.
При этом потоки могут быть прерваны операционной системой в любой момент и в любом месте, в том числе в критической секции
Однако следует заметить, что одно ограничение на прерывания все же имеется. Нельзя прерывать поток между выполнением операций проверки и установки блокирующей переменной.
Обобщением блокирующих переменных являются так называемые семафоры Дийкстры.
Вместо двоичных переменных Дийкстра (Dijkstra) предложил использовать переменные, которые могут принимать целые неотрицательные значения.
Такие переменные, используемые для синхронизации вычислительных процессов, получили название семафоров.
Для работы с семафорами вводятся два примитива, традиционно обозначаемых Р и V.
Пусть переменная S представляет собой семафор.
Тогда действия V(S) и P(S) определяются следующим образом.
V(S): переменная S увеличивается на 1 единым действием.(Выборка, наращивание и запоминание не могут быть прерваны).
P(S): уменьшение S на 1, если это возможно. Если S=0 и невозможно уменьшить S, оставаясь в области целых неотрицательных значений, то в этом случае поток, вызывающий операцию Р, ждет, пока это уменьшение станет возможным.
Успешная проверка и уменьшение также являются неделимой операцией.
Рассмотрим использование семафоров на классическом примере взаимодействия двух выполняющихся в режиме мультипрограммирования потоков, один из которых пишет данные в буферный пул, а другой считывает их из буферного пула.
Пусть буферный пул состоит из N буферов, каждый из которых может содержать одну запись.
В общем случае поток-писатель и поток-читатель могут иметь различные скорости и обращаться к буферному пулу с переменой интенсивностью.
В один период скорость записи может превышать скорость чтения, в другой — наоборот.
Для правильной совместной работыпоток-писатель должен приостанавливаться, когда все буферы оказываются занятыми, и активизироваться при освобождениихотя бы одного буфера.
Напротив, поток-читатель должен приостанавливаться, когда все буферы пусты, и активизироваться при появлении хотя бы одной записи.
Введем два семафора: е — число пустых буферов, и f — число заполненных буферов, причем в исходном состоянии е =N, a f =0. Тогда работа потоков с общим буферным пулом может быть описана следующим образом (рис.).
Рис.Использование семафоров для синхронизации потоков
Поток-писатель прежде всего выполняет операцию Р(е), с помощью которой он проверяет, имеются ли в буферном пуле незаполненные буферы.
В соответствии с семантикой операции Р, если семафор е равен 0 (то есть свободных буферов в данный момент нет), то поток-писатель переходит в состояние ожидания.
Если же значением е является положительное число, то он уменьшает число свободных буферов, записывает данные в очередной свободный буфер