Knigi-for.me

Linux программирование в примерах - Роббинс Арнольд

Тут можно читать бесплатно Linux программирование в примерах - Роббинс Арнольд. Жанр: Интернет издательство , год . Так же Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте knigi-for.me (knigi for me) или прочесть краткое содержание, предисловие (аннотацию), описание и ознакомиться с отзывами (комментариями) о произведении.

Типичная высокоуровневая структура основанного на сигналах приложения выглядит таким образом:

for(;;){

 /* <i>Ожидание сигнала</i> */

 /* <i>Обработка сигнала</i> */

}

Оригинальным интерфейсом V7 для ожидания сигнала является

pause()
:

#include &lt;unistd.h&gt; /* POSIX */

int pause(void);

pause()
приостанавливает процесс; она возвращается лишь после того, как сигнал будет доставлен и его обработчик вернется из вызова. По определению,
pause()
полезна лишь с перехваченными сигналами — игнорируемые сигналы при их появлении игнорируются, а сигналы с действием по умолчанию, завершающим процесс (с созданием файла образа или без него), продолжают действовать так же.

Проблема в только что описанной высокоуровневой структуре приложения кроется в части «Обработка сигнала». Когда этот код запускается, вы не захотите обрабатывать другой сигнал; вы хотите завершить обработку текущего сигнала до перехода к следующему. Одним из возможных решений является структурирование обработчика сигнала таким образом, что он устанавливает флаг и проверяет его в главном цикле:

volatile sig_atomic_t signal_waiting = 0; /* true, если не обрабатываются сигналы */

void handler(int sig) {

 signal_waiting = 1;

 /* Установка других данных, указывающих вид сигнала */

В основном коде флаг проверяется:

for (;;) {

 if (!signal_waiting) { /* Если возник другой сигнал, */

  pause(); /* этот код пропускается */

  signal_waiting = 1;

 }

 /* Определение поступившего сигнала */

 signal_waiting = 0;

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

}

К сожалению, этот код изобилует условиями гонки:

for (;;) {

 if (!signal_waiting) {

  /* &lt;--- Сигнал может появиться здесь, после проверки условия! */

  pause(); /* pause() будет вызвана в любом случае */

  signal_waiting = 1;

 }

 /* Определение поступившего сигнала

    &lt;--- Сигнал может переписать здесь глобальные данные */

 signal_waiting = 0;

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

    &lt;--- То же и здесь, особенно для нескольких сигналов */

}

Решением является блокирование интересующего сигнала в любое время, кроме ожидания его появления. Например, предположим, что интересующим нас сигналом является

SIGINT
:

void handler(int sig) {

 /* sig автоматически блокируется функцией sigaction() */

 /* Установить глобальные данные, касающиеся этого сигнала */

}

int main(int argc, char **argv) {

 sigset_t set;

 struct sigaction act;

 /* ...обычная настройка, опции процесса и т.д. ... */

 sigemptyset(&amp;set); /* Создать пустой набор */

 sigaddset(&amp;set, SIGINT); /* Добавить в набор SIGINT */

 sigprocmask(SIG_BLOCK, &amp;set, NULL); /* Заблокировать его */

 act.sa_mask = set; /* Настроить обработчик */

 act.sa_handler = handler;

 act.sa_flags = 0;

 sigaction(sig, &amp;act, NULL); /* Установить его */

 ... /* Возможно, установить отдельные обработчики */

 ... /* для других сигналов */

 sigemptyset(&amp;set); /* Восстановить пустой, допускает SIGINT */

 for (;;) {

  sigsuspend(&amp;set); /* Ждать появления SIGINT */

  /* Обработка сигнала. SIGINT здесь снова блокируется */

 }

 /* ...любой другой код... */

 return 0;

}

Ключом к использованию этого является то, что

sigsuspend()
временно заменяет маску сигналов процесса маской, переданной в аргументе. Это дает
SIGINT
возможность появиться. При появлении он обрабатывается; обработчик сигнала возвращается, а вслед за ним возвращается также
sigsuspend()
. Ко времени возвращения
sigsuspend()
первоначальная маска процесса снова на месте.

Вы легко можете расширить этот пример для нескольких сигналов, блокируя в

main()
и в обработчике все интересующие сигналы и разблокируя их лишь в вызове
sigsuspended()
.

При наличии всего этого не следует в новом коде использовать

pause()
.
pause()
был стандартизован POSIX главным образом для поддержки старого кода. То же самое верно и для функции
sigpause()
System V Release 3. Вместо этого, если нужно структурировать свое приложение с использованием сигналов для IPC, используйте исключительно функции API
sigsuspend()
и
sigaction()
.

ЗАМЕЧАНИЕ. Приведенный выше код предполагает, что маска сигналов процесса начинается пустой. Код изделия должен вместо этого работать с любой маской сигналов, имеющейся на момент запуска программы.

10.8. Важные сигналы специального назначения

Некоторые сигналы имеют особое назначение. Здесь мы опишем наиболее важные.


Роббинс Арнольд читать все книги автора по порядку

Роббинс Арнольд - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки kniga-for.me.

Все материалы на сайте размещаются его пользователями.
Администратор сайта не несёт ответственности за действия пользователей сайта..
Вы можете направить вашу жалобу на почту knigi.for.me@yandex.ru или заполнить форму обратной связи.