Сигналы межпроцессного взаимодействия
Сигна́лы межпроцессного взаимодействия — являются сообщениями, которые операционная система посылает процессу, или один процесс посылает другому. С точки зрения пользователя получение процессом сигнала выглядит как возникновение исключительной ситуации (прерывания). Когда процесс получает сигнал, выполнение программы процесса прерывается, и управление передается на подпрограмму (функцию) — обработчик сигнала. После выполнения обработчика сигнала выполнение прерванной программы возобновляется с той точки, на которой она была прервана.[1][2]
Типы сигналов
Типы сигналов задаются числовыми номерами, но при программировании для них обычно используют символьные имена (константы), определённые в системных включаемых файлах. В операционной системе предусмотрено большое число типов сигналов, но большинство из этих типов зарезервировано для системных целей — это сигналы, которые операционная система посылает процессу. Однако есть и сигналы, которыми процессы могут обмениваться между собой.
В рамках полномочий пользователя процесс может послать сигнал любому другому процессу, PID которого ему известен, при помощи системного вызова kill (несмотря на грозное название, этот системный вызов не обязательно убивает тот процесс, которому он адресован).
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int signal);
Аргумент pid указывает процесс, которому посылается сигнал, а аргумент signal — какой сигнал посылается.
- если pid > 0, сигнал посылается процессу с идентификатором pid;
- если pid = 0, сигнал посылается всем процессам в группе, к которой принадлежит посылающий процесс;
- если pid = −1 и посылающий процесс не является процессом суперпользователя, то сигнал посылается всем процессам в системе, для которых идентификатор пользователя совпадает с эффективным идентификатором пользователя процесса, посылающего сигнал.
- если pid = −1 и посылающий процесс является процессом суперпользователя, то сигнал посылается всем процессам в системе, за исключением системных процессов (обычно всем, кроме процессов с pid = 0 и pid = 1);
- если pid < 0, но не −1, то сигнал посылается всем процессам из группы, идентификатор которой равен абсолютному значению аргумента pid (если позволяют привилегии);
- если signal = 0, то производится проверка на ошибку, а сигнал не посылается. Это можно использовать для проверки правильности аргумента pid (есть ли в системе процесс или группа процессов с соответствующим идентификатором).
Тип сигнала | Описание |
---|---|
SIGKILL | Этот сигнал приводит к завершению получившего его процесса. Это единственный сигнал, который не может игнорироваться и для которого нельзя назначить собственный обработчик |
SIGTERM | Этот сигнал — запрос на завершение процесса. Выдачу этого сигнала, например, включает в себя команда (не системный вызов!) kill. Подразумевается, что процесс, получивший этот сигнал, должен завершиться, однако процесс может установить игнорирование этого сигнала или назначить для него собственный обработчик. |
SIGCHLD | Этот сигнал система посылает родительскому процессу при завершении любого его дочернего процесса. Реакция на этот сигнал, установленная по умолчанию, — игнорирование. Родительский процесс может не заботиться об обработке этого сигнала, если только он не хочет использовать его для синхронизации своего выполнения с дочерним процессом. |
SIGALRM | Этот сигнал используется для отсчета временных интервалов. Процесс может установить некоторый временной интервал при помощи системных вызовов alarm или setitimer, и по истечении заданного интервала система пошлет ему сигнал SIGALRM. |
SIGUSR1 и SIGUSR2 | За этими сигналами не зарезервированы никакие системные назначения. Процессы могут посылать эти сигналы друг другу и интерпретировать их по своему усмотрению.[1] |
Установка собственных обработчиков сигналов
Для установки своего обработчика сигнала, для его отмены или для установки игнорирования сигнала используется системный вызов signal.
# include <signal.h>
void (*signal (int sig, void (*handler) (int)))(int);
Параметр sig — это номер сигнала, обработку которого предстоит изменить. Параметр handler описывает новый способ обработки сигнала — это может быть указатель на пользовательскую функцию-обработчик сигнала, специальное значение SIG_DFL (восстановить реакцию процесса на сигнал sig по умолчанию) или специальное значение SIG_IGN (игнорировать поступивший сигнал sig).
Системный вызов возвращает указатель на старый способ обработки сигнала, значение которого можно использовать для восстановления старого способа в случае необходимости. Обработчик сигнала в процессе имеет вид функции с прототипом:
void имя_функции(int sigtype);
Параметром данной функции является тип сигнала (один и тот же обработчик может быть установлен для обработки сигналов разных типов).
Пример пользовательской обработки сигнала SIGUSR1.
void *my_handler(int nsig) { код функции-обработчика сигнала } int main() { (void) signal(SIGUSR1, my_handler); }
ОС в которых можно использовать сигналы
Сигналы можно использовать во всех Unix системах таких как BSD, FreeBSD, GNU и т. д.
В windows есть небольшой аналог, функция signal() из CRT, из сигналов которой по сути только SIGINT можно использовать по назначению.
Примечания
- Архитектура UNIX. Процессы Глава 1. Введение в операционную систему UNIX (недоступная ссылка). Дата обращения: 11 мая 2016. Архивировано 5 июня 2016 года.
- Лекция 8: Средства межпроцессного взаимодействия