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

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

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, где создается дочерний процесс и канал связи.) Прежде всего обратите внимание, что.



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.
Копирование материалов разрешено исключительно при условии цититирования.