Главная страница Взаимодействие нетривиальных процессов 12 struct sigevent sigev: 13 if (argc !- 2) 14 err quit( usage: mqnotifysig3 <name> ): 15 /* открытие очереди, получение атрибутов, выделение буфера */ 16 mqd = Mq open(argv[l]. 0 ROONLY 0 NONBLOCK): 17 Mq getattr(mqd. &attr): 18 buff = Malloc(attr.mq msgsize): 19 Sigemptyset(&zeromask): /* сигналы не блокируются */ 20 Sigemptyset(&newmask): 21 Sigemptyset(&oldmask): 22 Sigaddset(&newmask, SIGUSRl): 23 /* установка обработчика, включение уведомления */ 24 Signal(SIGUSRl, sig usrl): 25 sigev. sigev notify = SIGEVJIGNAL; 26 sigev.sigev signo = SIGUSRl: 27 Mq notify(mqd, &sigev): 28 for ( : : ) { 29 Sigprocmask(SIG BLOCK, &newmask. &oldmask): /* блокируем SIGUSRl */ 30 while (mqflag == 0) 31 sigsuspend(&zeromask): 32 mqflag - 0: /* сброс флага */ 33 Mq notify(mqd, &sigev): /* перерегистрируемся */ 34 while ( (n = mq receive(mqd, buff, attr.mq msgsize, NULL)) >= 0) { 35 printf( read %й bytes\n , (long) n): 36 } 37 if (errno != EAGAIN) 38 err sys( mq receive error ): 39 Sigprocmask(SIG UNBLOCK, &newmask, NULL): /* разблокируем SIGUSRl */ 40 } 41 exit(O): 42 } 43 Static void 44 sig usrl(int signo) 45 { 46 mqflag = 1: 47 return, 48 } Открытие очереди сообщений в режиме отключенной блокировки 15-18 Первое изменение в программе: при открытии очереди сообщений указывается флаг 0 NONBLOCK. Считывание всех сообщений из очереди 34-38 Другое изменение: mq recei ve вызывается в цикле, считывая все сообщения в очереди, пока не будет возвращена ошибка с кодом EAGAIN, означающая отсутствие сообщений в очереди. Пример: уведомление с использованием sigwait вместо обработчика Хотя программа из предыдущего примера работает правильно, можно повысить ее эффективность. Программа использует si gsuspend для блокировки в ожидании прихода сообщения. При помещении сообщения в пустую очередь вызывается сигнал, основной поток останавливается, запускается обработчик, который устанавливает флаг mqf 1 ад, затем снова запускается главный поток, он обнаруживает, что значение mqflag отлично от нуля, и считывает сообщение. Более простой и эффективный подход заключается в блокировании в функции, ожидающей получения сигнала, что не требует вызова обработчика только для установки флага. Эта возможность предоставляется функцией sigwait: #include <signal .li> int sigwait(const sigset t *set. int *sig): /* Возвращает 0 в случае успешного завершения. -1 - в случае ошибки */ Перед вызовом sigwait мы блокируем некоторые сигналы. Набор блокируемых сигналов указывается в качестве аргумента set. Функция sigwait блокируется, пока не придет по крайней мере один из этих сигналов. Когда он будет получен, функция возвратит его. Значение этого сигнала сохраняется в указателе sig, а функция возвращает значение 0. Это называется синхронным ожиданием асинхронного события: мы используем сигнал, но не пользуемся асинхронным обработчиком сигнала. В листинге 5.11 приведен текст программы, использующей mq noti fy и sigwait. Листинг 5.11. Использование mq notify совместно с sigwait pxmsg/mqnotifysig4.c 1 #include unpipcli 2 int 3 maindnt argc. char **argv) 5 int signo: 6 niqd t mqd: 7 void *buff; 8 ssize t n: 9 sigset t newmask: 10 struct mq attr attr: 11 struct sigevent sigev: 12 if (argc != 2) 13 err quit( usage: mqnotifysig4 <name> ): 14 /* открытие очереди, получение атрибутов, выделение буфера */ 15 mqd = Mq open(argv[l], 0 ROONLY 0 NONBLOCK): 16 Mq getattr(mqd, &attr): 17 buff = Malloc(attr.mq msgsize): 18 Sigemptyset(&newmask): 19 Sigaddset(&newmask. SIGUSRl): 20 Sigprocmask(SIG BLOCK, &newmask. NULL): /* блокируем SIGUSRl */ 21 /* установка обработчика, включение уведомления */ 22 sigev.sigev notify = SIGEV SIGNAL: 23 sigev.sigev signo = SIGUSRl: 24 Mq notify(niqd, &sigev): 25 for ( : : ) { 26 SigwaiK&newmask. &signo): 27 if (signo == SIGUSRl) { 28 Mq notify(mqd. &sigev): /* перерегистрируемся */ 29 while ( (n = niq receive(mqd. buff. attr.niq msgsize. NULL)) >= 0) { 30 printfCread Id bytes\n . (long) n): 31 } 32 if (errno != EAGAIN) 33 err sys( niq receive error ); 34 } 35 } 36 exit(O): 37 } Инициализация набора сигналов и блокировка SIGUSR1 18-20 Инициализируется один набор сигналов, содержащий только SIGUSRl, а затем этот сигнал блокируется sigprocmask. Ожидание сигнала 26-34 Мы блокируем выполнение программы и ждем прихода сигнала, вызвав si gwai t. При получении сигнала SIGUSRl мы перерегистрируемся на уведомление и считываем все доступные сообщения. ПРИМЕЧАНИЕ - Функция sigwait часто используется в многопоточных процессах. Действительно, глядя на прототип функции, мы можем заметить, что возвращаемое значение будет О нли одной из ошибок Еххх, что весьма похоже на функции Pthread. Однако в многопоточном процессе нельзя пользоваться sigprocmask - вместо нее следует вызывать pthread sigmask, которая изменяет маску сигналов только для вызвавшего ее потока. Аргументы pthreadsigmask совпадают с аргументами sigprocmask. Существуют два варианта функции sigwait: sigwaitinfo возвращает структуру .siginfot (которая будет определена в следующем разделе) и предназначена для использования с надежными сигналами; функция sigtimedwait также возвращает структуру siginfot и позволяет вызывающему процессу установить ограничение по времени на ожидание. Большая часть книг о многопоточном программировании, таких как [3], рекомендуют пользоваться sigwait для обработки всех сигналов в многопоточном процессе и не использовать асинхронные обработчики. Пример: очереди сообщений Posix и функция select Дескриптор очереди сообщений (переменная типа nKid t) не является обычным дескриптором и не может использоваться с функциями sel ect и pol 1 (глава 6 [24]), Тем не менее их можно использовать вместе с каналом и функцией mq noti fy. (Аналогичный метод применен в разделе 6.9 для очередей System V, где создается дочерний процесс и канал связи.) Прежде всего обратите внимание, что.
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |