Вход/Регистрация
Основы программирования в Linux
вернуться

Мэтью Нейл

Шрифт:

Применение сигналов и приостановка выполнения — важные составляющие программирования в ОС Linux. Это означает, что программа необязательно должна выполняться все время. Вместо того чтобы долго работать в цикле, проверяя, не произошло ли событие, она может ждать его наступления. Это особенно важно в многопользовательской среде, где процессы совместно используют один процессор, и такой вид деятельного ожидания оказывает большое влияние на производительность системы. Особая проблема, связанная с сигналами, заключается в том, что вы никогда не знаете наверняка, что произойдет, если сигнал появится в середине системного вызова? (Ответ весьма неудовлетворительный: все зависит от ситуации.) Вообще следует беспокоиться только о "медленных" системных вызовах, таких как считывание с терминала, когда системный вызов может вернуться с ошибкой, если сигнал появится во время его пребывания в режиме ожидания. Если вы начнете применять сигналы в своих программах, нужно учитывать, что некоторые системные вызовы могут закончиться аварийно, если сигнал создаст ошибочную ситуацию, которую вы могли не принимать во внимание до того, как добавили обработку сигналов.

Нужно тщательно программировать сигналы, потому что существует ряд "состояний гонок", возникающих в программах, применяющих сигналы. Например, если вы намерены вызвать pause для ожидания сигнала и этот сигнал возникнет до вызова pause, ваша программа может ждать неопределенно долго события, которое не произойдет. Новоиспеченный программист сталкивается с множеством таких состояний гонок, важных проблем синхронизации или согласования времени. Всегда очень внимательно проверяйте программный код, использующий сигналы.

Надежный интерфейс сигналов

Мы рассмотрели подробно возбуждение и перехват сигналов с помощью

signal
и родственных функций, поскольку они очень часто применяются в старых UNIX-программах. Тем не менее, стандарты X/Open и спецификации UNIX рекомендуют более современный программный интерфейс для сигналов
sigaction
, который более надежен.

#include <signal.h>

int sigaction<int sig, const struct sigaction *act, struct sigaction *oact);

Структура

sigaction
, применяемая для определения действий, предпринимаемых при получении сигнала, заданного в аргументе
sig
, определена в файле signal.h и как минимум включает следующие элементы:

void (*)(int)sa_handler /* функция, SIG_DFL или SIG_IGN */

sigset_t sa_mask /* сигналы, заблокированные для sa_handler */

int sa_flags /* модификаторы действий сигнала */

Функция

sigaction
задает действие, связанное с сигналом
sig
. Если
oact
не
null
,
sigaction
записывает предыдущее действие для сигнала в указанное
oact
место. Если
act
равен
null
, это все, что делает функция
sigaction
. Если указатель
act
не
null
, задается действие для указанного сигнала.

Как и функция

signal
,
sigaction
возвращает 0 в случае успешного выполнения и -1 в случае ошибки. Переменная
errno
получит значение
EINVAL
, если заданный сигнал некорректен или была предпринята попытка захватить или проигнорировать сигнал, который нельзя захватывать или игнорировать.

В структуре

sigaction
, на которую указывает аргумент
act
,
sa_handler
— это указатель на функцию, вызываемую при получении сигнала
sig
. Она очень похожа на функцию
func
, которая, как вы видели раньше, передавалась функции
signal
. Вы можете применять специальные значения
SIG_IGN
и
SIG_DFL
в поле
sa_handler
для обозначения того, что сигнал должен игнорироваться или должно быть восстановлено действие по умолчанию, соответственно.

Поле

sa_mask
описывает множество сигналов, которые будут добавлены в маску сигналов процесса перед вызовом функции
sa_handler
. Это множество сигналов, которые блокируются и не должны доставляться процессу. Такое поведение мешает возникновению ситуации, описанной ранее, в которой сигнал был получен до того, как его обработчик дошел до завершения. Применение поля
sa_mask
может устранить это состояние гонок.

Однако сигналы, захватываемые обработчиками, заданными в структуре

sigaction
, по умолчанию не восстанавливаются, и нужно задать в поле
sa_flags
значение
SA_RESETHAND
, если хотите добиться поведения, виденного вами раньше при обсуждении функции
signal
. Прежде чем обсуждать подробнее
sigaction
, давайте перепишем программу ctrlc.c, применяя
sigaction
вместо функции
signal
(упражнение 11.9).

Упражнение 11.9. Функция
sigaction

Внесите приведенные далее изменения, так чтобы сигнал

SIGINT
перехватывался
sigaction
. Назовите новую программу ctrlc2.c.

#include <signal.h>

#include <stdio.h>

#include <unistd.h>

void ouch(int sig) {

 printf("OUCH!
– I got signal %d\n", sig);

}

int main {

 struct sigaction act;

 act.sa_handler = ouch;

 sigemptyset(&act.sa_mask);

 act.sa_flags = 0;

 sigaction(SIGINT, &act, 0);

 while (1) {

printf("Hello World!\n");

sleep(1);

 }

  • Читать дальше
  • 1
  • ...
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: