Главная страница Взаимодействие нетривиальных процессов Листинг 10.19 (продолжение) 67 Sem post(&shared.nempty); /* освободилось место для объекта */ 68 } 69 } Пустая критическая область 40-42 Критическая область, защищаемая семафором mutex, в данном примере пуста. Если бы буферы данных представляли собой связный список, здесь мы могли бы удалять буфер из списка, не конфликтуя при этом с производителем. Но в нашем примере, где мы просто переходим к следующему буферу с единственным потоком-производителем, защищать нам просто нечего. Тем не менее мы оставляем операции установки и снятия блокировки, подчеркивая, что они могут потребоваться в новых версиях кода. Считывание данных и увеличение семафора nstored 43-49 Каждый раз, когда производитель получает пустой буфер, он вызывает функцию read. При возвращении из read увеличивается семафор nstored, уведомляя потребителя о том, что буфер готов. При возвращении функцией read значения О (конец файла) семафор увеличивается, а производитель завершает работу. Поток-потребитель 57-68 Поток-потребитель записывает содержимое буферов в стандартный поток вывода. Буфер, содержащий нулевой объем данных, обозначает конец файла. Как и в потоке-производителе, критическая область, защищенная семафором mutex, пуста. ПРИМЕЧАНИЕ В разделе 22.3 книги [24] мы разработали пример с несколькими буферами. В этом примере производителем был обработчик сигнала SIGIO, а потребитель представлял собой основной цикл обработки (функцию dgecho). Разделяемой переменной был счетчик nqueue. Потребитель блокировал сигнал SIGIO на время проверки или изменения счетчика 10.12. Использование семафоров несколькими процессами Правила совместного использования размещаемых в памяти семафоров несколькими процессами просты: сам семафор (переменная типа sem t, адрес которой является первым аргументом sem init) должен находиться в памяти, разделяемой всеми процессами, которые хотят его использовать, а второй аргумент функции sem init должен быть равен 1. ПРИМЕЧАНИЕ - Эти правила аналогичны требованиям к разделению взаимного исключения, условной переменной или блокировки чтения-записи между процессами: средство синхронизации (переменная типа pthread mutex t, pthread cond t или pthread rwlock t) должно находиться в разделяемой памяти и инициализироваться с атрибутом PTHREAD PROCESS SHARED. Что касается именованных семафоров, процессы всегда могут обратиться к одному и тому же семафору, указав одинаковое имя при вызове sem open. Хотя указатели, возвращаемые sem open отдельным процессам, могут быть различны, все функции, работающие с семафорами, будут обращаться к одному и тому же именованному семафору. Что произойдет, если мы вызовем функцию seni open, возвращающую указатель на тип seni t, а затем вызовем fork? В описании функции fork в стандарте Posix. 1 говорится, что все открытые родительским процессом семафоры будут открыты и в дочернем процессе . Это означает, что нижеследующий код верен: sem t *mutex; /* глобальный указатель, копируемый, при вызове forkO */ /* родительский процесс создает именованный семафор */ mutex = Sem open(PxJpc name(NAME), 0 CREAT OJXCL. FILE MODE. 0): if ( (childpid = ForkO) == 0) { /* дочерний процесс */ Sem wait(mutex): /* родительский процесс */ Sem post(mutex): ПРИМЕЧАНИЕ Причина, по которой следует аккуратно относиться к передаче семафоров при порождении процессов, заключается в том, что состояние семафора может храниться в переменной типа sem t, но для его работы может требоваться и другая информация (например, дескрипторы файлов). В следующей главе мы увидим, что семафоры System V однозначно определяются их целочисленными идентификаторами, возвращаемыми функцией semget. Любой процесс, которому известен идентификатор, может получить доступ к семафору. Вся информация о семафоре System V хранится в ядре, а целочисленный идентификатор просто указывает номер семафора ядру. 10.13. Ограничения на семафоры Стандартом Posix определены два ограничения на семафоры: ш SEM NSEMS MAX - максимальное количество одновременно открытых семафоров для одного процесса (Posix требует, чтобы это значение было не менее 256); Ш SEM VALUE MAX - максимальное значение семафора (Posix требует, чтобы оно было не меньше 32 767). Две эти константы обычно определены в заголовочном файле <uni std, h> и могут быть получены во время выполнения вызовом sysconf, как мы показываем ниже. Пример: программа semsysconf Программа в листинге 10.20 вызывает sysconf и выводит два ограничения на семафоры, зависящие от конкретной реализации. Листинг 10.20. Вызов sysconf для получения ограничений на семафоры pxsem/semsysconf.с 1 finclude unpipc.h 2 int 3 main(int argc. char **argv) 5 printf( SEM NSEMS MAX - %M. SEM VALUE MAX - %Шг\ . 6 Sysconf(JC SEM NSEMS MAX). Sysconf( SC SEM VALUE MAX)): 7 exit(O); При запуске этой программы в наших двух тестовых системах получим следующий результат: Solaris % semsysconf SEMS NSEMS MAX = 2147483647, SEM VALUE MAX = 2147483647 alpha % semsysconf SEMS NSEMS MAX - 256, SEM VALUE MAX = 32767 10.14. Реализация с использованием FIFO Займемся реализацией именованных семафоров Posix с помощью каналов FIFO. Именованный семафор реализуется как канал FIFO с конкретным именем. Неотрицательное количество байтов в канале соответствует текущему значению семафора. Функция sem post помещает 1 байт в канал, а sem wait считывает его оттуда (приостанавливая выполнение процесса, если канал пуст, а именно этого мы и хотим). Функция sem open создает канал FIFO, если указан флаг 0 CREAT; открывает его дважды (один раз на запись, другой - на чтение) и при создании нового канала FIFO помещает в него некоторое количество байтов, указанное в качестве начального значения. ПРИМЕЧАНИЕ - Этот и последующие разделы данной главы содержат усложненный материал, который можно при первом чтении пропустить. Приведем текст нашего заголовочного файла semaphore. h, определяющего фундаментальный тип sem t (листинг 10.21). Листинг 10.21. Заголовочный файл semaphore.h my pxsem fi fо/semaphore.h 1 /* фундаментальный тип */ 2 typedef struct { 3 int sem fd[2]: /* два дескриптора fd: [0] для чтения. [1] для записи */ 4 int sem magic; /* магическое число */ 5 } mysem t: 6 fdefine SEM MAGIC 0x89674523 7 fifdef SEMJAILED 8 fundef SEMJAILED 9 fdefine SEMJAILED ((mysemj *)(-l)) /* чтобы компилятор не выдавал предупреждений*/ 10 fendif
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |