Скачиваний:
53
Добавлен:
02.05.2014
Размер:
258.56 Кб
Скачать

9.5. Семафоры

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

При работе с именованным семафором один из процессов должен создать системный семафор при помощи вызова createSemaphore, другие процессы получают доступ к созданному системному семафору при помощи вызова openSemaphore. Среди входных параметров этих вызовов имеется внешнее имя семафора, вызовы возвращают манипулятор для семафора, используемый для его идентификации при последующей работе с ним. При окончании работы с системным семафором процесс должен выполнить вызов closeSemaphore. Семафор уничтожается, когда он закрыт во всех процессах, его использовавших.

Выполнение операций над семафором может обеспечиваться системным вызовом вида:

flag = semaphoreOp(semaphorId, opCode,

waitOption);

где semaphorId – манипулятор семафора, opCode – код операции, waitOption – опция ожидания, flag – возвращаемое значение, признак успешного выполнения операции или код ошибки.

Помимо основных для семафоров P- и V-операций конкретные семафорные API ОС могут включать в себя расширенные и сервисные функции, такие как безусловная установка семафора, установка семафора с ожиданием его очистки, ожидание очистки семафора. При выполнении системных вызовов – аналогов P-операции, как правило, имеется возможность задать опцию ожидания – блокировать процесс, если выполнение P-операции невозможно, или завершить системный вызов с признаком ошибки.

Во многих современных ОС наряду с семафорами "в чистом виде" API представляет те же семафоры и в виде "прикладных" объектов – объектов взаимного исключения и событий. Хотя содержание этих объектов одно и то же – семафор, ОС в отношении этих объектов представляет для прикладных процессов специфическую семантику API, соответствующую задачам взаимного исключения и синхронизации.

Все современные ОС предоставляют прикладному процессу возможность работать с "массивами семафоров", то есть задавать список семафоров и выполнять операцию над всем списком, например, ожидать очистки любого в заданном списке. Наиболее развито это средство в ОС Unix, где имеется возможность выполнять за один системный вызов semop (аналог нашего semaphoreOp) сразу нескольких различных операций над несколькими семафорами, причем весь список операций выполняется как одна транзакция.

Неименованные семафоры обычно используются как средство взаимного исключения и синхронизации работы нитей одного процесса.

9.6. Программные каналы

Программный канал по-английски называется pipe (труба), и это весьма удачное название. Канал действительно можно представить как трубопровод пневматической почты, проложенный между двумя процессами, как показано на рисунке 9.1. По этому трубопроводу данные передаются от одного процесса к другому. Как и трубопровод, программный канал однонаправленный (хотя, например, в Unix одним системным вызовом создаются сразу два разнонаправленных канала). Как и трубопровод, программный канал имеет собственную емкость: данные, записанные в канал, не обязательно должны немедленно выбираться на противоположном его конце, но могут накапливаться в канале, пока это позволяет его емкость. Как и трубопровод, канал работает по дисциплине FIFO: первый вошел – первый вышел.

Рисунко 9.1 Программные каналы

Из всех средств взаимодействия между процессами программные каналы лучше всего вписываются в модель виртуальных коммуникационных портов. Канал для процесса практически аналогичен файлу. Специальные системные вызовы типа createPipe, openPipe используются для создания канала и получения доступа к каналу, а для работы с каналом используются те же вызовы read и write, что и для файлов, и даже закрытие канала выполняется файловым системным вызовом close. При создании канала для него создается дескриптор, как для открытого файла, что позволяет работать с ним далее, как с файлом. Канал, однако, представляет собой не внешние данные, а область памяти. Для канала выделяется память в системной области, что может ограничивать емкость канала.

Наиболее часто используются неименованные каналы как средство связи между родителем и потомком. Операция создания неименованного канала возвращает два файловых манипулятора: для чтения и для записи. Процесс-предок передает эти манипуляторы процессу-потомку. Если связь между предком и потомком однонаправленная, то каждый из них закрывает канал по одному из манипуляторов. Например, если данные передаются только от предка к потомку, то предок после передачи манипуляторов закрывает канал на чтение, а потомок – на запись. Пример установления такой связи в ОС Unix приведен в главе 11, во фрагменте программы командного интерпретатора.

С точки зрения реализации канал представляет собой классический вариант задачи "производитель–потребитель": один процесс пишет в канал данные, другой – читает их из канала. Если при попытке записи данных в канал обнаруживается, что канал полон, пишущий процесс блокируется до освобождения места в канале, если при попытке чтения данных обнаруживается, что канал пуст, читающий процесс блокируется до появления в канале данных. Внутренним механизмом ОС, обеспечивающим синхронизацию в таких ситуациях, является, конечно же, семафор.

Именованные каналы представляют собой удобное средство клиент/серверных коммуникаций. Именованные каналы в некоторых ОС (например, OS/2) существенно отличаются от неименованных. Именованные каналы ориентированы в этих системах прежде всего на взаимодействие процессов в сетевой среде (или, точнее, для них прозрачно, находятся ли оба процесса на одном компьютере или в разных узлах сети). Такой канал двунаправленный, то есть к нему возможны обращения и для чтения, и для записи. Данные в канале могут передаваться как потоком байт, так и сообщениями. В последнем случае каждое сообщение снабжается заголовком, в котором указывается его длина. К одному концу канала постоянно подключен процесс, его создавший, – владелец или сервер, к другому концу могут подключаться различные процессы-клиенты, таким образом, обмен данными по именованному каналу между процессами, ни один из которых не является владельцем канала, невозможен. При создании канала (системный вызов createNamedPipe) указывается максимально возможное число клиентов, которые могут быть одновременно подключены к каналу (это число, впрочем, может и не ограничиваться). Когда владелец создает канал, последний находится в так называемом отключенном состоянии. Системным вызовом connectNamedPipe владелец переводит канал в ждущее состояние. Теперь процессы-клиенты могут подключаться к другому концу канала при помощи файловых системных вызовов openNamedPipe. Канал, открытый хотя бы одним клиентом, считается подключенным, сервер и подключенные клиенты могут работать с ним, используя вызовы файлового API. Клиенты отключаются от канала вызовом close, в распоряжении владельца есть вызов disconnectNamedPipe – разрыва канала. Помимо обычных вызовов файлового обмена для работы с именованным каналом в составе API могут быть специальные системные вызовы, обеспечивающие выполнение сложных транзакций на именованном канале, например: transactNamedPipe – взаимный обмен данными (вывод и ввод) за одну операцию, callNamedPipe – обеспечивает также открытие канала, взаимный обмен, закрытие канала. Кроме того, к именованному каналу или к нескольким именованным каналам может быть подключен семафор, который сбрасывается при изменении состояния канала (заполнен – не заполнен, пуст – не пуст).

Соседние файлы в папке Системное программирование и операционные системы