Синхронизация процессов при помощи семафоров
Когда процесс выдает запрос ввода-вывода, он блокирует себя в ожидании завершения соответствующей операции ввода-вывода. Заблокированный процесс должен быть активизирован каким-либо другим процессом. Подобное взаимодействие может служить примером функций, относящихся к протоколу блокирования/возобновления. Рассмотрим более общий случай, когда одному процессу необходимо, например, чтобы он получал уведомление о наступлении некоторого события. Предположим, что какой-либо другой процесс может обнаружить, что данное событие произошло. Программа рис. 4.10 показывает, каким образом при помощи семафора можно реализовать простой механизм синхронизации (блокирования/возобновления) для двух процессов. program блокированиевозобновления; var событие: семафор; procedure процессодин; Begin предшествующиеоператорыодин; Р(событие); прочиеоператорыодин End; procedure процессдва; Begin предшествующиеоператорыдва; V(событие); прочиеоператорыдва End; Begin инициализадйясемафора (событие, 0);
процессодин; процессдва Parend End; Здесь "процессодин" выполняет некоторые "предшествующие операторыодин", а затем операцию Р (событие). Ранее при инициализации семафор был установлен в нуль, так что "процессодин" будет ждать. Со временем "процессдва" выполнит операцию V (событие), сигнализируя о том, что данное событие произошло. Тем самым, "процессодин" получает возможность продолжить свое выполнение. Отметим, что подобный механизм будет выполнять свои функции даже в том случае, если "процессдва" обнаружит наступление события и просигнализирует об этом еще до того, как "процессодин", выполнит операцию Р (событие); при этом семафор переключится из 0 в 1, так что операция Р (событие) просто произведет обратное переключение, из 1 в 0, и "процессодин" продолжит свое выполнение без ожидания. 4.13 Пара "производитель-потребитель" Когда в последовательной программе одна процедура вызывает другую и передает ей данные, обе эти процедуры являются частями единого процесса - они не выполняются параллельно. Если, однако, один процесс передает данные другому процессу, возникают определенные проблемы. Подобная передача может служить примером взаимодействия, или обмена информацией между процессами. program парапроизводительпотребитель; var исключительныйдоступ: семафор; числозанесено: семафор; буферчисла: целое; procedure процесспроизводитель; var следующийрезультат: целое; Begin while истина do Begin вычислениеследующегорезультата; Р(исключительныйдоступ); буферчисла:= следующийрезультат; V(исключительныйдоступ); V(числозанесено) End End; procedure процесспотребитель; var следующийрезультат: целое; Begin while истина do Begin Р(числозанесено); Р(исключительныйдоступ); следующийрезультат:= буферчисла; V(исключительныйдоступ); записать (следующий результат) End End; Begin инициализациясемафора(исключительныйдоступ, 1); инициализациясемафора(числозанесено, 0);
процесспроизводитель; процесспотребитель Parend End; Рассмотрим следующую пару (отношение) "производитель – потребитель". Предположим, что один процесс, источник, или производитель, генерирует информацию, которую другой процесс, получатель, или потребитель, использует. Предположим, что они взаимодействуют при помощи одной разделяемой целой переменной с именем "буферчисла". Процесс-производитель производит некоторые вычисления, а затем заносит результат в "буферчисла"; процесс-потребитель читает "буферчисла" и печатает результат. Возможно, что эти процессы, производитель и потребитель, работают в достаточно близком темпе либо резко различаются по скоростям. Если каждый раз, когда процесс-производитель помещает свой результат в "буферчисла", процесс-потребитель будет немедленно считывать и печатать его, то на печать будет верно выдаваться та последовательность чисел, которую формировал процесс-производитель. Предположим теперь, что скорости обоих процессов резко различны. Если процесс-потребитель работает быстрее, чем процесс-производитель, он может прочитать и напечатать одно и то же число дважды (или в общем случае много раз), прежде чем процесс-производитель выдаст следующее число. Если же процесс-производитель работает быстрее, чем потребитель, он может записать новый результат на место предыдущего до того, как процесс-потребитель успеет прочитать и напечатать этот предшествующий результат; процесс-производитель, работающий с очень высокой скоростью, фактически может по нескольку раз перезаписывать результат, так что будет потеряно много результатов. Очевидно, что здесь мы хотели бы обеспечить такое взаимодействие процесса-производителя и процесса-потребителя, при котором данные, заносимые в «буферчисла», никогда не терялись бы и не дублировались. Создание подобного режима взаимодействия является примером синхронизации процессов. На рис. 4.11 показана параллельная программа, в которой для реализации взаимодействия в паре "производитель – потребитель" применяются операции над семафорами. В этой программе мы ввели два семафора: "исключительныйдоступ" используется для обеспечения доступа к разделяемой переменной в режиме взаимоисключения, а "числозанесено" - для обеспечения синхронизации процессов.
|