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 байт. Как мы уже отмечали, эта операция относится к разрешенным для асинхронных обработчиков.

<p>Пример: запуск нового потока</p>

Альтернативой снятию блокировки сигналом является присваивание sigev_notify значения SIGEV_THREAD, что приводит к созданию нового потока. Функция, указанная в sigev_notify_function, вызывается с параметром sigev_value. Атрибуты нового канала указываются переменной sigev_notify_attributes, которая может быть и нулевым указателем, если нас устраивают устанавливаемые по умолчанию атрибуты. Текст программы приведен в листинге 5.13.

Листинг 5.13. Функция mq_notify, запускающая новый программный поток

//pxmsg/mqnotifythread1.с

1  #include "unpipc.h"

2  mqd_t mqd;

3  struct mq_attr attr;

4  struct sigevent sigev;

5  static void notify_thread(union sigval); /* наш поток */

6  int

7  main(int argc, char **argv)

8  {

9   if (argc != 2)

10   err_quit("usage: mqnotifythread1 name");

11  mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK);

12  Mq_getattr(mqd, attr);

13  sigev.sigev_notify = SIGEV_THREAD;

14  sigev.sigev_value.sival_ptr = NULL;

15  sigev.sigev_notify_function = notify_thread;

16  sigev.sigev_notify_attributes = NULL;

17  Mq_notify(mqd, sigev);

18  for (;;)

19   pause; /* новый поток делает все */

20  exit(0);

21 }

22 static void

23 notify_thread(union sigval arg)

24 {

25  ssize_t n;

26  void *buff;

27  printf("notify_thread started\n");

28  buff = Malloc(attr.mq_msgsize);

29  Mq_notify(mqd, sigev); /* перерегистрируемся */

30  while ((n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) = 0) {

31   printf("read %ld bytes\n", (long) n);

32  }

33  if (errno != EAGAIN)

34   err_sys("mq_receive error");

35  free(buff);

36  pthread_exit(NULL);

37 }

Мы задаем нулевой указатель в качестве аргумента нового потока (sigev_value), поэтому функции start нового потока ничего не передается. Мы могли бы передать указатель на дескриптор, вместо того чтобы декларировать его как глобальный, но новому потоку все равно нужно получать атрибуты очереди сообщений и структуру sigev (для перерегистрации). Мы также указываем нулевой указатель в качестве атрибутов нового потока, поэтому используются установки по умолчанию. Новые потоки создаются как неприсоединенные (detached threads).

ПРИМЕЧАНИЕ

К сожалению, ни одна из использовавшихся для проверки примеров систем (Solaris 2.6 и Digital Unix 4.0B) не поддерживает SIGEV_THREAD. Обе они допускают только два значения sigev_notify: SIGEV_NONE и SIGEV_SIGNAL.

<p>5.7. Сигналы реального времени Posix</p>

За прошедшие годы сигналы в Unix много раз претерпевали революционные изменения.

1. Модель сигналов, предлагавшаяся в Unix Version 7 (1978), была ненадежной. Сигналы могли быть потеряны, и процессу было трудно отключить отдельные сигналы при выполнении отдельных участков кода.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже