Семафор — специальный объект операционной системы, над которым определены две базовые операции: операция закрытия и операция открытия. Семафорный объект может быть доступен одновременно нескольким процессам (это обеспечивается операционной системой) и в этом смысле он представляет собой разделяемый ресурс.
Основой семафора является семафорная переменная S, которая в случае простейшего (двоичного) семафора может принимать значения 0 или 1. Значение 0 соответствует "закрытому" состоянию семафора, значение 1 — "открытому". Операции закрытия и открытия семафора изменяют значение семафорной переменной.
Действия, выполняемые операцией закрытия семафора:
- Проверить значение семафорной переменной S.
- Если S=1 (семафор открыт), присвоить S значение 0 ("закрыть" семафор).
- Если S=0 (семафор уже закрыт), перевести процесс, пытающийся закрыть семафор, в состояние ожидания (состояние блокировки).
Действия, выполняемые операцией открытия семафора:
- Если в списке заблокированных процессов находится процесс, ожидающий открытия данного семафора, перевести этот процесс в состояние готовности.
- Если в списке заблокированных процессов нет процесса, ожидающего открытия данного семафора, присвоить S значение 1 ("открыть" семафор)
Так как семафор доступен одновременно нескольким процессам, возможна ситуация, когда несколько процессов одновременно попытаются выполнить операцию открытия или закрытия. Чтобы этого избежать, операции открытия и закрытия семафора защищаются от одновременного вызова несколькими процессами на уровне операционной системы. Для этого на время выполнения указанных операций в ОС отключается передиспетчеризация процессов. Так как операции открытия и закрытия семафора являются короткими и выполняются за ограниченное малое время, такое временное отключение диспетчеризации не вызывает сколь-нибудь серьезных проблем.
Как же используются семафоры? Посмотрим на следующий пример. Пусть Sem — объект типа "семафор", предоставленный операционной системой. Sem.Open — операция открытия семафора, Sem.Close — операция закрытия.
Пример 1
Program 6;
procedure Proc1;
begin
While True do {Бесконечный цикл, выполняемый в процессе}
begin
Sem.Close; {Закрытие семафора}
CrBlock1; {Критический блок}
Sem.Open; {Открытие семафора}
................... {Другие операции процесса, не входящие в КУ}
end;
end;
procedure Proc2;
begin
While True do {Бесконечный цикл, выполняемый в процессе}
begin
Sem.Close; {Закрытие семафора}
CrBlock2; {Критический блок}
Sem.Open; {Открытие семафора}
................... {Другие операции процесса, не входящие в КУ}
end;
end;
begin
Par_begin {Запуск параллельных процессов}
Proc1;
Proc2;
Par_end;
end.
Как видно, техника использования семафоров предельно проста. Перед входом в КУ процесс закрывает семафор. При этом все другие процессы "засыпают" на закрытом семафоре при входе в свои КУ. После выхода из КУ процесс открывает семафор, давая возможность "заснувшим на входе" процессам войти в свои КУ.
Таким образом, использование семафора является простой и удобной техникой синхронизации асинхронных процессов. Как видно, прим. 1 содержит минимум кода, обеспечивающего собственно синхронизацию, так как основная работа выполняется операционной системой.