Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 [ 32 ] 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

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

4. При помещении сообщения в пустую очередь, для которой имеется зарегистрированный на уведомление процесс, оно будет отправлено только в том случае, если нет заблокированных в вызове mqrecei ve для этой очереди процессов. Таким образом, блокировка в вызове mq receive имеет приоритет перед любой регистрацией на уведомление.

5. При отправке уведомления зарегистрированному процессу регистрация снимается. Процесс должен зарегистрироваться снова (если в этом есть необходимость), вызвав mq noti fy еще раз.

ПРИМЕЧАНИЕ -

С сигналами в Unix всегда была связана одна проблема: действие сигнала сбрасывалось на установленное по умолчанию каждый раз при отправке сигнала (раздел 10.4 [21]). Обычно первой функцией, вызываемой обработчиком сигнала, была signal, переопределявшая обработчик. Это создавало небольшой временной промежуток между отправкой сигнала и переопределением обработчика, в который процесс мог быть завершен при повторном появлении того же сигнала. На первый взгляд может показаться, что та же проблема должна возникать и при использовании mq notify, поскольку процесс должен перерегистрироваться каждый раз после появления уведомления. Однако очереди сообщений отличаются по своим свойствам от сигналов, поскольку необходимость отправки уведомления не может возникнуть, пока очередь не будет пуста. Следовательно, необходимо аккуратно перерегистрироваться на получение уведомления до считывания пришедшего сообщения из очереди.

Пример: простая программа с уведомлением

Прежде чем углубляться в тонкости сигналов реального времени и потоков Posix, мы напишем простейшую программу, включающую отправку сигнала SIGUSR1 при помещении сообщения в пустую очередь. Эта программа приведена в листинге 5.8, и мы отметим, что она содержит ошибку, о которой мы вскоре поговорим подробно.

Листинг 5.8. Отправка S1GUSR1 при помещении сообщения в пустую очередь (неправильная версия программы)

pxmsg/mqnotifysigl.c

1 #lnclude unpipc.h

2 niqd t mqd:

3 void *buff:

4 struct mq attr attr:

5 struct sigevent sigev:

6 static void sig usrl(int):

7 int

8 mainCint argc. char **argv)

10 if (argc != 2)

11 err quit( usage: mqnotifysigl <name> ): продолжение



Листинг 5.8 (продолжение)

12 /* открываем очередь, получаем атрибуты, выделяем буфер */

13 mqd = Mq open(argv[l]. 0 RDONLY):

14 Mq getattr(mqd. &attr):

15 buff = Mailoc(attr.mq msgsize):

16 /* устанавливаем обработчик, включаем уведомление */

17 - Signal(SIGUSRl. sig usrl):

18 sigev.sigev notify = SIGEV SIGNAL:

19 sigev.sigev signo = SIGUSRl:

20 Mq notify(mqd. Ssigev):

21 for ( : ; )

22 pauseO: /* все делает обработчик */

23 exit(O):

24 }

25 static void

26 sig usrl(int signo)

27 {

28 ssize t n:

29 Mq notify(mqd. Ssigev): /* сначала перерегистрируемся */

30 n = Mq receive(mqd. buff. attr.mq msgsize. NULL):

31 printfC SIGUSRl received, read ld bytesXn . (long) n):

32 return:

33 }

Объявление глобальных переменных

2-6 Мы объявляем несколько глобальных переменных, используемых совместно функцией main и нашим обработчиком сигнала (sigusrl).

Открытие очереди, получение атрибутов, выделение буфера чтения

12-15 Мы открываем очередь сообщений, получаем ее атрибуты и выделяем буфер считывания соответствующего размера.

Установка обработчика сигнала, включение уведомления

16-20 Сначала мы устанавливаем свой обработчик для сигнала SIGUSRl. Мы присваиваем полю sigev notify структуры sigevent значение SIGEV SIGNAL, что говорит системе о необходимости отправки сигнала, когда очередь из пустой становится непустой. Полю s i деv s i gno присваивается значение, соответствующее тому сигналу, который мы хотим получить. Затем вызывается функция mq noti fy.

Бесконечный цикл

Функция mai п после этого зацикливается, й процесс приостанавливается при вызове pause, возвращающей -1 при получении сигнала.

Получение сигнала, считывание сообщения

Обработчик сигнала вызывает mq noti fy для перерегистрации, считывает сообщение и выводит его длину. В этой программе мы игнорируем приоритет полученного сообщения.



ПРИМЕЧАНИЕ -

Оператор return в конце sig usrl не требуется, поскольку возвращаемое значение отсутствует, а конец текста функции неявно предусматривает возвращение в вызвавшую программу. Тем не менее автор всегда записывает return явно, чтобы указать, что возвращение из этой функции может происходит с особенностями. Например, может произойти преждевременный возврат (с ошибкой EINTR) в потоке, обрабатывающем сигнал.

Запустим теперь эту программу в одном из окон

Solaris % mqcreate /testl Solaris % mqnotifysigl /testl

и затем выполним следующую команду в другом окне

Solaris % mqsend /testl 50 16

Как и ожидалось, программа mqnotifysigl выведет сообщение: SIGUSR1 received.

read 50 bytes.

Мы можем проверить, что только один процесс может быть зарегистрирован на получение уведомления в любой момент, запустив копию программы в другом окне:

Solaris % mqnotifysigl /testl mq notify error: Device busy

Это сообщение соответствует коду ошибки EBUSY.

Сигналы Posix: функции типа Async-Signal-Safe

Недостаток программы из листинга 5.8 в том, что она вызывает niq noti fy, niq recei ve и printf из обработчика сигнала. Ни одну из этих функций вызывать оттуда не следует.

Функции, которые могут быть вызваны из обработчика сигнала, относятся к группе, называемой, согласно Posix, async-signal-safe functions (функции, обеспечивающие безопасную обработку асинхронных сигналов). В табл. 5.1 приведены эти функции по стандарту Posix вместе с некоторыми дополнительными, появившимися только в Unix 98.

Функции, которых нет в этом списке, не должны вызываться из обработчика сигнала. Обратите внимание, что в списке отсутствуют стандартные функции библиотеки ввода-вывода и функции pthread XXX для работы с потоками. Из всех функций IPC, рассматриваемых в этой книге, в список попали только sem post, read и write (подразумевается, что последние две используются с программными каналами и FIFO).

ПРИМЕЧАНИЕ -

Стандарт ANSI С указывает четыре функции, которые могут быть вызваны из обработчика сигналов: abort, exit, longjmp, signal. Первые три отсутствуют в списке функций async-signal-safe стандарта Unix 98.

Таблица 5.1. Функции, относящиеся к группе async-signal-safe

access fpathconf rename sysconf

aio return fstat rmdir tcdrain

aio suspend fsync sem post tcflow -продолжен!



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 [ 32 ] 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.