Книга: UNIX: взаимодействие процессов

Пример: очереди сообщений Posix и функция select

Пример: очереди сообщений Posix и функция select

Дескриптор очереди сообщений (переменная типа mqd_t) не является «обычным» дескриптором и не может использоваться с функциями select и poll (глава 6 [24]). Тем не менее их можно использовать вместе с каналом и функцией mq_notify. (Аналогичный метод применен в разделе 6.9 для очередей System V, где создается дочерний процесс и канал связи.) Прежде всего обратите внимание, что, согласно табл. 5.1, функция write принадлежит к группе async-signal-safe, поэтому она может вызываться из обработчика сигналов. Программа приведена в листинге 5.12.

Листинг 5.12. Использование уведомления с помощью сигнала и канала

//pxmsg/mqnotifysig5.c
1  #include "unpipc.h"
2  int pipefd[2];
3  static void sig_usr1(int);
4  int
5  main(int argc, char **argv)
6  {
7   int nfds;
8   char c;
9   fd_set rset;
10  mqd_t mqd;
11  void *buff;
12  ssize_t n;
13  struct mq_attr attr;
14  struct sigevent sigev;
15  if (argc != 2)
16   err_quit("usage: mqnotifysig5 <name>");
17  /* открытие очереди, получение атрибутов, выделение буфера */
18  mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK);
19  Mq_getattr(mqd, &attr);
20  buff = Malloc(attr.mq_msgsize);
21  Pipe(pipefd);
22  /* установка обработчика, включение уведомления */
23  Signal(SIGUSR1, sig_usr1);
24  sigev.sigev_notify = SIGEV_SIGNAL;
25  sigev.sigev_signo = SIGUSR1;
26  Mq_notify(mqd, &sigev);
27  FD_ZERO(&rset);
28  for (;;) {
29   FD_SET(pipefd[0], &rset);
30   nfds = Select(pipefd[0] + 1, &rset, NULL, NULL, NULL);
31   if (FD_ISSET(pipefd[0], &rset)) {
32    Read(pipefd[0], &c, 1);
33    Mq_notify(mqd, &sigev); /* перерегистрируемся */
34    while ((n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) >= 0) {
35     printf("read %ld bytesn", (long) n);
36    }
37    if (errno != EAGAIN)
38     err_sys("mq_receive error");
39   }
40  }
41  exit(0);
42 }
43 static void
44 sig_usr1(int signo)
45 {
46  Write(pipefd[1], "", 1); /* один байт – 0 */
47  return;
48 }

Создание канала

21 Мы создаем канал, в который обработчик сигнала произведет запись, когда будет получено уведомление о поступлении сообщения в очередь. Это пример использования канала внутри одного процесса.

Вызов select

27-40 Мы инициализируем набор дескрипторов rset и при каждом проходе цикла включаем бит, соответствующий дескриптору pipefd[0] (открытый на считывание конец канала). Затем мы вызываем функцию select, ожидая получения единственного дескриптора, хотя в типичном приложении именно здесь осуществлялось бы размножение дескрипторов одного из концов канала. Когда появляется возможность читать из канала, мы перерегистрируемся на уведомление и считываем все доступные сообщения.

Обработчик сигнала

43-48 Единственное, что делает обработчик сигнала, — записывает в канал 1 байт. Как мы уже отмечали, эта операция относится к разрешенным для асинхронных обработчиков.

Оглавление книги


Генерация: 1.720. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз