Применение IPC в обработчике сигнала функции

Применение IPC в обработчике сигнала функции

Существует еще один корректный путь решения нашей проблемы. Вместо того чтобы просто возвращать управление и, как мы надеемся, прерывать блокированную функцию recvfrom, наш обработчик сигнала при помощи средств IPC (Interprocess Communications — взаимодействие процессов) может сообщить функции dg_cli о том, что время таймера истекло. Это аналогично предложению, сделанному нами раньше, когда обработчик сигнала устанавливал глобальную переменную had_alarm по истечении времени таймера. Глобальная переменная использовалась как некая разновидность IPC (поскольку она была доступна и нашей функции, и обработчику сигнала). Однако при таком решении наша функция должна была проверять эту переменную, что могло привести к проблемам синхронизации в том случае, когда сигнал доставлялся приблизительно в это же время.

Листинг 20.6 демонстрирует использование канала внутри процесса. Обработчик сигналов записывает в канал 1 байт, когда истекает время таймера, а наша функция dg_cli считывает этот байт, чтобы определить, когда завершить свой цикл for. Что замечательно в этом решении — проверка готовности канала осуществляется функцией select. С ее помощью мы проверяем, готов ли к считыванию сокет или канал.

Листинг 20.6. Использование канала в качестве IPC между обработчиком сигнала и нашей функцией

//bcast/dgclibcast6.c

 1 #include "unp.h"

 2 static void recvfrom_alarm(int);

 3 static int pipefd[2];

 4 void

 5 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)

 6 {

 7  int n, maxfdp1;

 8  const int on = 1;

 9  char sendline[MAXLINE], recvline[MAXLINE + 1];

10  fd_set rset;

11  socklen_t len;

12  struct sockaddr *preply_addr;

13  preply_addr = Malloc(servlen);

14  Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

15  Pipe(pipefd);

16  maxfdp1 = max(sockfd, pipefd[0]) + 1;

17  FD_ZERO(&rset);

18  Signal(SIGALRM, recvfrom_alarm);

19  while (Fgets(sendline, MAXLINE, fp) != NULL) {

20   Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

21   alarm(5);

22   for (;;) {

23    FD_SET(sockfd, &rset);

24    FD_SET(pipefd[0], &rset);

25    if ((n = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {

26     if (errno == EINTR)

27      continue;

28     else

29      err_sys("select error");

30    }

31    if (FD_ISSET(sockfd, &rset)) {

32     len = servlen;

33     n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr,

34      &len);

35     recvline[n] = 0; /* null terminate */

36     printf("from %s: %s",

37     Sock_ntop_host(preply_addr, len), recvline);

38    }

39    if (FD_ISSET(pipefd[0], &rset)) {

40     Read(pipefd[0], &n, 1); /* истекшее время */

41     break;

42    }

43   }

44  }

45  free(preply_addr);

46 }

47 static void

48 recvfrom_alarm(int signo)

49 {

50  Write(pipefd[1], "", 1); /* в канал пишется один нулевой байт */

51  return;

52 }

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

15 Мы создаем обычный канал Unix. Возвращаются два дескриптора: pipefd[0] доступен для чтения, а pipefd[0] — для записи.

ПРИМЕЧАНИЕ

Мы могли бы использовать функцию socketpair и получить двусторонний канал. В некоторых системах, особенно SVR4, обычный канал Unix всегда является двусторонним, и мы можем и читать, и записывать на любом конце этого канала.

Функция select на сокете и считывающем конце канала

23-30 Мы вызываем функцию select и на сокете, и на считывающем конце канала.

47-52 Когда доставляется сигнал SIGALRM, наш обработчик сигналов записывает в канал 1 байт, в результате чего считывающий конец канала становится готовым для чтения. Наш обработчик сигнала также возвращает управление, возможно, прерывая функцию select. Следовательно, если функция select возвращает ошибку EINTR, мы игнорируем эту ошибку, зная, что считывающий конец канала также готов для чтения, что завершит цикл for.

Чтение из канала

38-41 Когда считывающий конец канала готов для чтения, мы с помощью функции read считываем нулевой байт, записанный обработчиком сигнала, и игнорируем его. Но прибытие этого нулевого байта указывает нам на то, что истекло время таймера, и мы с помощью функции break выходим из бесконечного цикла for.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Конвертеры сигнала

Из книги Компьютер + TV: телевидение на ПК автора Гольцман Виктор Иосифович

Конвертеры сигнала Рассмотрим второй, очень важный компонент системы спутникового телевидения – конвертер сигнала. Конвертер представляет собой небольшой электронный блок, находящийся в фокусе спутниковой антенны. Он собирает сигнал, отраженный от зеркала тарелки,


Методы и технологии модуляции сигнала

Из книги Домашние и офисные сети под Vista и XP автора Ватаманюк Александр Иванович

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


12.1.1. Жизненный цикл сигнала

Из книги Разработка приложений в среде Linux. Второе издание автора Джонсон Майкл К.

12.1.1. Жизненный цикл сигнала Сигналы имеют четко определенный жизненный цикл: они создаются, сохраняются до тех пор, пока ядро не выполнит определенное действие на основе сигнала, а затем вызывают совершение этого действия. Создание сигнала называют по-разному: поднятие


12.7.1. Получение контекста сигнала

Из книги QNX/UNIX [Анатомия параллелизма] автора Цилюрик Олег Иванович

12.7.1. Получение контекста сигнала Информация о том, как и почему был сгенерирован сигнал, называется контекстом[68] сигнала. Приложения, которые должны видеть этот контекст, используют обработчики сигналов, отличающиеся от нормальных. Они включают два дополнительных


20.2. Выдача звукового сигнала

Из книги Язык Си - руководство для начинающих автора Прата Стивен

20.2. Выдача звукового сигнала Заставить консоль генерировать звуковой сигнал в течение определенного периода времени на указанной частоте совсем не сложное дело. Для этого существуют два способа. Первый состоит во включении или отключении постоянной тональной посылки.


Традиционная обработка сигнала

Из книги Операционная система UNIX автора Робачевский Андрей М.

Традиционная обработка сигнала В этой части изложения мы рассмотрим традиционные модели перехвата сигналов и установки для них собственных обработчиков (в том числе и игнорирование или восстановление стандартной обработки по умолчанию). Термин «традиционный» здесь


Применение функции scanf( ) 

Из книги Linux и UNIX: программирование в shell. Руководство разработчика. автора Тейнсли Дэвид

Применение функции scanf( )       Поскольку в дальнейшем мы будем пользоваться функция scanf( ) лишь эпизодически, мы рассмотрим здесь только основные особенности ее применения.      Так же как для функции printf( ), для функции scanf( ) указываются управляющая строка и следующий за


Отправление сигнала

Из книги UNIX: разработка сетевых приложений автора Стивенс Уильям Ричард

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


Доставка и обработка сигнала

Из книги автора

Доставка и обработка сигнала Для каждого сигнала в системе определена обработка по умолчанию, которую выполняет ядро, если процесс не указал другого действия. В общем случае существуют пять возможных действий: завершить выполнение процесса (с созданием образа core и без),


26.2.2. Обнаружение сигнала

Из книги автора

26.2.2. Обнаружение сигнала Некоторые сигналы можно захватить и выполнить соответствующие действия. Другие сигналы нельзя уловить. Например, если команда получает сигнал 9, пользователю не нужно предпринимать какие?либо действия.Если ограничиться написанием сценариев,


26.3.2. Захват сигнала и выполнение действий

Из книги автора

26.3.2. Захват сигнала и выполнение действий Наиболее часто выполняемым действием является удаление временных файлов.В следующем сценарии с помощью команд df и ps непрерывно добавляется информация во временные файлы HOLD1.$$ и HOLD2.$$. Не забывайте, что символы $$ заменяют ID


5.9. Обработка сигнала SIGCHLD

Из книги автора

5.9. Обработка сигнала SIGCHLD Назначение состояния зомби — сохранить информацию о дочернем процессе, чтобы родительский процесс мог ее впоследствии получить. Эта информация включает идентификатор дочернего процесса, статус завершения и данные об использовании ресурсов


Блокирование и разблокирование сигнала с помощью функции pselect

Из книги автора

Блокирование и разблокирование сигнала с помощью функции pselect Одним из корректных решений будет использование функции pselect (см. раздел 6.9), как показано в листинге 20.3.Листинг 20.3. Блокирование и разблокирование сигналов с помощью функции pselect//bcast/dgclibcast4.с 1 #include "unp.h" 2 static


25.3. Эхо-сервер UDP с использованием сигнала SIGIO

Из книги автора

25.3. Эхо-сервер UDP с использованием сигнала SIGIO В этом разделе мы приведем пример, аналогичный правой части рис. 25.1: UDP-сервер, использующий сигнал SIGIO для получения приходящих дейтаграмм. Этот пример также иллюстрирует использование надежных сигналов стандарта POSIX.В данном