Главная страница Взаимодействие нетривиальных процессов ния значения семафора поток помечался как готовый к выполнению. Никаких изменений в работе программы не произойдет, если вместо вызвавшего sempost потока будет выполняться другой, ожидавший изменения состояния семафора (исследуйте такую ситуацию и убедитесь в этом самостоятельно). Перечислим три главных отличия семафоров и взаимных исключений в паре с условными переменными: 1. Взаимное исключение всегда должно разблокироваться тем потоком, который установил блокировку, тогда как увеличение значения семафора не обязательно осуществляется ожидающим его изменения потоком. Это мы только что продемонстрировали на примере. 2. Взаимное исключение может быть либо заблокировано, либо разблокировано (пара состояний, аналогично бинарному семафору). 3. Поскольку состояние семафора хранится в определенной переменной, изменение его значения оказывает влияние на процессы, которые вызовут функцию wai t уже после этого изменения, тогда как при отправке сигнала по условной переменной в отсутствие ожидающих его потоков сигнал будет утерян. Взгляните на листинг 10.2 и представьте, что при первом проходе цикла производителем потребитель еще не вызвал semwait. Производитель сможет поместить объект в буфер, вызвать sem post для семафора get (увеличивая его значение с О до 1), а затем он заблокируется в вызове semwait для семафора put. Через некоторое время потребитель дойдет до цикла for и вызовет sem wa i t для переменной get, что уменьшит значение этого семафора с 1 до О, а затем потребитель приступит к обработке содержимого буфера. ПРИМЕЧАНИЕ- В Обосновании Posix.l (Rationale) содержится следующий комментарий по поводу добавления семафоров помимо взаимных исключений и условных переменных: Семафоры включены в стандарт в первую очередь с целью предоставить средства синхронизации выполнения процессов; эти процессы могут и не использовать общий сегмент памяти. Взаимные исключения и условные переменные описаны как средства синхронизации потоков, у которых всегда есть некоторое количество общей памяти. Оба метода широко используются уже много лет. Каждое из этих простейших средств имеет свой предпочтительный круг задач . В разделе 10.15 мы увидим, что для реализации семафоров-счетчиков с живучестью ядра требуется написать около 300 строк кода на С, использующего взаимные исключения и условные переменные. Несмотря на предпочтительность применения семафоров для синхронизации между процессами и взаимных исключений для синхронизации между потоками, и те и другие могут использоваться в обоих случаях. Следует пользоваться тем набором средств, который удобен в данном приложении. Выше мы отмечали, что стандартом Posix описано два типа семафоров: именованные (named) и размещаемые в памяти (memory-based или unnamed). На рис. 10.4 сравниваются функции, используемые обоими типами семафоров. Именованный семафор Posix был изображен на рис. 10.2. Неименованный, или размещаемый в памяти, семафор, используемый для синхронизации потоков одного процесса, изображен на рис. 10.5, именованный семафор sem open () неименованный семафор sem init О sem wait () semjrywait () sem post О sem getvalue () sem close () sem destroy () sem unlink () - , Рис. 10.4. Вызовы для семафоров Posix один процесс I Рис. 10.5. Семафор, размещенный в общей памяти двух потоков На рис. 10.6 изображен размещенный в разделяемой памяти семафор (часть 4), используемый двумя процессами. Общий сегмент памяти принадлежит адресному пространству обоих процессов.
один процесс один процесс разделяемая память Рис. 10.6. Семафор, размещенный в разделяемой двумя процессами памяти В этой главе сначала рассматриваются именованные семафоры Posix, а затем - размещаемые в памяти. Мы возвращаемся к задаче производителей и потребителей из раздела 7.3 и расширяем ее, позволяя нескольким производителям работать с одним потребителем, а в конце концов переходим к нескольким производителям и нескольким потребителям. Затем мы покажем, что часто используемый при реализации ввода-вывода метод множественных буферов является частным случаем задачи производителей и потребителей. Мы рассмотрим три реализации именованных семафоров Posix: с использованием каналов FIFO, отображаемых в память файлов и семафоров System V. 10.2. Функции sem open, sem close и sem unrmk Функция semopen создает новый именованный семафор или открывает существующий. Именованный семафор может использоваться для синхронизации выполнения потоков и процессов: linclude <semaphore.h> sem t *sem open(const char *пдте. int oflag. ... /* mode t nvde. unsigned int value */ ): /* Возвращает указатель на семафор в случае успешного завершения. SEM FAILED - в случае ошибки */ Требования к аргументу пате приведены в разделе 2.2. Аргумент oflag может принимать значения 0,0 CREAT, 0 CREAT 0 EXCL, как описано в разделе 2.3. Если указано значение 0 CREAT, третий и четвертый аргументы функции являются обязательными. Аргумент mode указывает биты разрещений доступа (табл. 2.3), а value указывает начальное значение семафора. Это значение не может превышать константу SEM VALUE MAX, которая, согласно Posix, должна быть не менее 32 767. Бинарные семафоры обычно устанавливаются в 1, тогда как семафоры-счетчики чаще инициализируются большими величинами. При указании флага 0 CREAT (без 0 EXCL) семафор инициализируется только в том случае, если он еще не существует. Если семафор существует, ошибки не возникнет. Ошибка будет возвращена только в том случае, если указаны флаги 0 CREAT I 0 EXCL. Возвращаемое значение представляет собой указатель на тип semt. Этот указатель впоследствии передается в качестве аргумента функциям seffl cl ose, sein wai t, sein trywait, sein post и sein getvalue. ПРИМЕЧАНИЕ- Кажется странным возвращать SEM FAILED в случае ошибки - нулевой указатель был бы более уместен. В ранних версиях стандарта Posix указывалось возвращаемое значение -1, и во многих реализациях константа SEM FAILED определена как Idefine SEM FAILED ((sem t *)(-!)) В Posix.l мало говорится о битах разрешений, связываемых с семафором при его создании и открытии. Вспомните, мы говорили в связи с табл. 2.2 о том, что для именованных семафоров не нужно даже указывать флаги 0 RDONLY, 0 WRONLY и 0 RDWR. В системах, на которых мы тестируем все программы этой книги (Digital Unix 4.0В и Solaris 2.6), для работы с семафором (его открытия) необходимо иметь к нему доступ как на чтение, так и на запись. Причина, скорее всего, в том, что обе операции, выполняемые с семафором (post и wait), состоят из считывания текущего значения и последующего его изменения. Отсутствие доступа на чтение или запись в этих реализациях приводит к возвращению функцией sem open ошибки EACCESS ( Permission denied ). Открыв семафор с помощью semopen, можно потом закрыть его, вызвав sem close: linclude <semaphore.h> int sem close(seni t *sem): /* Возвращает 0 в случае успешного завершения. -1 - в случае ошибки */
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |