Главная страница Взаимодействие нетривиальных процессов Таблица 5.1 (продолжение)
Пример: уведомление сигналом Одним из способов исключения вызова 1?аких-либо функций из обработчика сигнала является установка этим обработчиком глобального флага, который проверяется программным потоком для получения информации о приходе сообщения. В листинге 5.9 иллюстрируется этот метод, хотя новая программа также содержит ошибку, но уже другую, о которой мы вскоре поговорим подробнее. Глобальная переменная 2 Поскольку единственное действие, выполняемое обработчиком сигнала, заключается в присваивании ненулевого значения флагу mqflag, глобальным переменным из листинга 5.8 уже не нужно являться таковыми. Уменьшение количества глобальных переменных - это всегда благо, особенно при использовании программных потоков. Открытие очереди сообщений 15-18 Мы открываем очередь сообщений, получаем ее атрибуты и выделяем буфер считывания. Инициализация наборов сигналов 19-22 Мы инициализируем три набора сигналов и устанавливаем бит для сигнала SIGUSRl в наборе newmask. Установка обработчика сигнала, включение уведомления 23-27 Мы устанавливаем обработчик сигнала для SIGUSRl, присваиваем значения полям структуры sigevent и вызываем mq noti fy. Листинг 5.9. Обработчик сигнала устанавливает флаг для главного потока (неправильная версия) pxmsg/mqnot i fy S1g2.с 1 #include unpipc.h 2 volatile sig atoniic t mqflag: /* ненулевое значение устанавливается обработчиком */ 3 static void sig usrl(int): 4 int 5 main(int argc, char **argv) 7 mqd t mqd: 8 void *buff: 9 ssize t n: 10 sigset t zeromask, newmask, oldmask; 11 struct mq attr attr: 12 struct sigevent sigev: 13 if (argc != 2) 14 err quit( usage: mqnbtifysig2 <name> ); 15 /* открытие очереди, получение атрибутов, выделение буфера */ 16 mqd - Mq open(argv[l], 0 ROONLY): 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 = SIGEV SIGNAL: 26 sigev. si gev 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 n = Mq receive(mqd, buff, attr.mq msgsize, NULL): 35 printf( read ld bytes\n , (long) n): 36 Sigprocmask(SIG UNBLOCK, &newmask, NULL): /* разблокируем SIGUSRl */ 37 } 38 exit(O): 39 } 40 static void 41 sig usrl(int signo) 42 { 43 mqf1ag = 1: 44 return: 45 ) Ожидание установки флага обработчиком 28-32 Мы вызываем sigprocmask, чтобы заблокировать SIGUSRl, сохраняя текущую маску сигналов в oldmask. Затем мы в цикле проверяем значение глобального флага mqflag, ожидая, когда обработчик сигнала установит его в ненулевое значение. Пока значение этого флага равно нулю, мы вызываем sigsuspend, что автоматически приостанавливает вызывающий поток и устанавливает его маску в zeromask (сигналы не блокируются). Раздел 10.16 [21] рассказывает о функции sigsuspend более подробно. Также там объясняются причины, по которым мы должны проверять значение переменной mqf 1 ад только при заблокированном сигнале SIGUSR1. Каждый раз при выходе из sigsuspend сигнал SIGUSRl блокируется. Перерегистрация и считывание сообщения 33-36 Когда флаг mqflag принимает ненулевое значение, мы регистрируемся на получение уведомления заново и считываем сообщение из очереди. Затем мы разблокируем сигнал SIGUSRl и возвращаемся к началу цикла. Мы уже говорили, что в этой версии программы также присутствует ошибка. Посмотрим, что произойдет, если в очередь попадут два сообщения, прежде чем будет считано первое из них. Мы можем имитировать это, добавив sleep перед вызовом mq noti fy. Проблема тут в том, что уведомление отсылается только в том случае, когда сообщение помещается в пустую очередь. Если в очередь поступают два сообщения, прежде чем первое будет считано, то отсылается только одно уведомление. Тогда мы считываем первое сообщение и вызываем sigsuspend, ожидая поступления еще одного. А в это время в очереди уже имеется сообщение, которое мы должны прочитать, но которое мы никогда не прочтем. Пример: уведомление сигналом с отключением блокировки Исправить описанную выше ошибку можно, отключив блокировку операции считывания сообщений. Листинг 5.10 содержит измененную версию программы из листинга 5.9. Новая программа считывает сообщения в неблокируемом режиме. Листинг 5.10. /1спользование уведомления с помощью сигнала для считывания сообщения из очереди сообщений Posix pxmsg/mqnotifysig3.c 1 #include unpipcli 2 volatile sig atoniic t mqflag; /* ненулевое значение устанавливается обработчиком сигнала */ 3 static void sig usrl(int): 4 int 5 mainCint argc. cliar **argv) 7 mqd t mqd; 8 void *buff: 9 ssize t n: 10 sigset t zeromask. newmask, oldmask: 11 struct mq attr attr;
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |