Категории
Самые читаемые
PochitayKnigi » Компьютеры и Интернет » Интернет » Linux программирование в примерах - Роббинс Арнольд

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

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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 151 152 153 154 155 156 157 158 159 ... 253
Перейти на страницу:

• Временной интервал, остающийся для alarm(), сохраняется на своем месте. (Другими словами, если процесс устанавливает alarm, а затем непосредственно вызывает exec(), новый образ в конечном счете получит SIGALARM. Если он сначала вызывает fork(), родитель сохраняет установки alarm, тогда как потомок, вызывающий exec(), не сохраняет.

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

10.10. Резюме

«Наша история до настоящего времени, эпизод III»

- Арнольд Роббинс (Arnold Robbins) -

• Интерфейсы обработки сигналов развились от простых, но подверженных состояниям гонок, до сложных, но надежных. К сожалению, множественность интерфейсов затрудняет их изучение по сравнению с другими API Linux/Unix.

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

• signal() и raise() стандартизованы ISO С. signal() управляет действиями для определенных сигналов; raise() посылает сигнал текущему процессу. Остаются ли обработчики сигналов установленными после вызова или сбрасываются для действия по умолчанию, зависит от реализации, signal() и raise() являются простейшими интерфейсами, для многих приложений их достаточно.

• POSIX определяет функцию bsd_signal(), которая подобна signal(), но гарантирует, что обработчик остается установленным.

• Действия, происходящие после возвращения из обработчика, варьируют в зависимости от системы. Традиционные системы (V7, Solaris, возможно, и другие) восстанавливают действие сигнала по умолчанию. На этих системах прерванный системный вызов возвращает -1, устанавливая в errno значение EINTR. Системы BSD оставляют обработчик установленным и возвращают -1 с errno, содержащим EINTR, лишь в случае, когда не было перемещения данных; в противном случае, системный вызов запускается повторно.

• GNU/Linux придерживается POSIX, который похож, но не идентичен с BSD. Если не было перемещения данных, системный вызов возвращает -1/EINTR. В противном случае он возвращает объем перемещенных данных. Поведение BSD «всегда повторный запуск» доступно через интерфейс sigaction(), но он не является действием по умолчанию.

• Обработчики сигналов, используемые с signal(), подвержены состояниям гонок. Внутри обработчиков сигналов должны использоваться исключительно переменные типа volatile sig_atomic_t. (В целях упрощения в некоторых из наших примеров мы не всегда следовали этому правилу.) Таким же образом, для вызова из обработчика сигналов безопасными являются лишь функции из табл. 10.2.

• Первоначальной попыткой создания надежных сигналов был API сигналов System V Release 3 (скопированный из BSD 4.0). Не используйте его в новом коде.

• POSIX API содержит множество компонентов:

  • маску сигналов процесса, перечисляющую текущие заблокированные сигналы;

  • тип sigset_t для представления масок сигналов, и функции sigfillset(), sigemptyset(), sigaddset(), sigdelset() и sigismember() для работы с ними;

  • функцию sigprocmask() для установки и получения маски сигналов процесса,

  • функцию sigpending() для получения набора ожидающих сигналов;

  • API sigaction() и struct sigaction во всем их великолепии.

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

• Механизмами POSIX для посылки сигналов являются kill() и killpg(). Они отличаются от raise() в двух отношениях: (1) одни процесс может послать сигнал другому процессу или целой группе процессов (конечно, с проверкой прав доступа), и (2) посылка сигнала 0 ничего не посылает, но осуществляет проверку. Таким образом, эти функции предоставляют способ проверки наличия определенного процесса или группы процессов и возможность посылки ему (им) сигнала.

• Сигналы могут использоваться в качестве механизма IPC, хотя такой способ является плохим способом структурирования приложения, подверженным состояниям гонок. Если кто-то держит приставленным к вашей голове ружье, чтобы заставить вас работать таким способом, для правильной работы используйте тщательное блокирование сигналов и интерфейс sigaction().

• SIGALARM и системный вызов alarm() предоставляют низкоуровневый механизм для уведомления о прошествии определенного числа секунд, pause() приостанавливает процесс, пока не появятся какие-нибудь сигналы, sleep() использует их для помещения процесса в спящее состояние на заданный период времени: sleep() и alarm() не должны использоваться вместе. Сама pause() создает состояние гонки; вместо этого нужно использовать блокирование сигналов и sigsuspend().

• Сигналы управления заданиями реализуют управление заданиями для оболочки. Большую часть времени следует оставлять их с установленными действиями по умолчанию, но полезно понимать, что иногда имеет смысл их перехватывать.

• Перехват SIGCHLD позволяет родителю узнать, что делает порожденный им процесс. Использование 'signal(SIGCHLD, SIG_IGN)' (или sigaction() с SA_NOCLDWAIT) вообще игнорирует потомков. Использование sigaction() с SA_NOCLDSTOP предоставляет уведомления лишь о завершении. В последнем случае, независимо от того, заблокирован SIGCHLD или нет, обработчики сигналов для SIGCHLD должны быть готовы немедленно обработать несколько потомков. Наконец, использование sigaction() без SA_NOCLDSTOP с обработчиком сигналов с тремя аргументами дает вам причину получения сигнала.

1 ... 151 152 153 154 155 156 157 158 159 ... 253
Перейти на страницу:
Тут вы можете бесплатно читать книгу Linux программирование в примерах - Роббинс Арнольд.
Комментарии