Сигналы, очереди сообщений и семафоры – три классических механизма IPC в Linux. Они пришли из UNIX, живут в ядре и до сих пор нужны в контейнерах, демонах, оркестрации и скриптах. Ниже – краткая история, как это устроено в kernel, API System V и POSIX, плюс рабочие примеры. Упор на то, что полезно DevOps и тем, кто пишет системный код, а не только «теория ОС».
История сигналов: от UNIX к Linux
Сигналы появились в UNIX в 1970-х (Ритчи, Томпсон) как способ уведомить процесс о событии: SIGINT, SIGCHLD и другие. UNIX System V (1983) встроил их в общую модель IPC. POSIX в 1980-е добавил сигналы реального времени (диапазон SIGRTMIN … SIGRTMAX). В Linux с 1991 года та же идея: сейчас доступно больше 60 сигналов, доставка и маски живут в структурах задачи.
История очередей сообщений: System V и POSIX
Очереди System V (1983) работают через ключи key_t и структуру msg_queue. POSIX-очереди (POSIX.1b, 1993) видны как объекты в /dev/mqueue: приоритеты, уведомления, удобнее для real-time и современного кода.
История семафоров: от Дейкстры до Linux
Семафоры формализовал Эдсгер Дейкстра в 1965: счётчик и операции P (уменьшить / ждать) и V (увеличить / разбудить). В UNIX System V (1983) они стали частью IPC для синхронизации между процессами. POSIX (1990-е, POSIX.1b) добавил именованные и неименованные семафоры, лучше стык с потоками. В Linux оба мира живут рядом: System V – legacy и сложные наборы, POSIX – проще API и futex под капотом.
Теория: как это выглядит в ядре
Сигналы
- Жизненный цикл: генерация (kill, sigqueue), очередь sigpending, доставка (get_signal), действие: SIG_DFL, SIG_IGN или свой обработчик.
- Код ядра: kernel/signal.c.
- Структуры: signal_struct в task_struct: sigpending, blocked, sigqueue.
Очереди сообщений
System V
- Хранение: цепочка msg_msg внутри msg_queue.
- API: msgsnd / msgrcv, выбор по mtype.
- Код: ipc/msg.c.
POSIX
- Создание: mq_open(“/name”, flags) и mq_attr (mq_maxmsg, mq_msgsize).
- Хранение: кольцевой буфер в /dev/mqueue, приоритеты сообщений 0-31.
- API: mq_send (добавить с приоритетом), mq_receive (забрать с максимальным приоритетом), mq_notify (уведомление через sigevent / сигнал).
- Код: ipc/mqueue.c.
Семафоры
System V
- Модель: массив семафоров (sem_array), операции semget, semctl, semop.
- Поля: semval, sempid, semncnt, semzcnt внутри struct sem.
- Код: ipc/sem.c. Часто всплывают SEM_UNDO и сложные наборы операций за один semop.
POSIX
- Модель: один семафор sem_t и простой API.
- Именованные: sem_open(“/name”, O_CREAT, mode, value), объекты в /dev/shm.
- Неименованные: sem_init(&sem, pshared, value) в shared memory или куче процесса.
- API: sem_wait (уменьшить / ждать при 0), sem_post (увеличить), sem_timedwait (с таймаутом).
- Реализация: kernel/futex.c + glibc.
Практика: короткие примеры
Сигналы
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void handler(int sig) {
printf("Сигнал %d\n", sig);
}
int main(void) {
signal(SIGUSR1, handler);
printf("PID: %d\n", getpid());
while (1)
sleep(1);
}
В другом терминале: kill -USR1 <pid>. Для продакшена обычно берут sigaction вместо signal – предсказуемее поведение и маски.
POSIX-очередь: отправитель
#include <mqueue.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(void) {
struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 128 };
mqd_t mq = mq_open("/myqueue", O_CREAT | O_WRONLY, 0644, &attr);
mq_send(mq, "High priority", 14, 10);
mq_close(mq);
return 0;
}
POSIX-очередь: получатель
#include <mqueue.h>
#include <stdio.h>
int main(void) {
mqd_t mq = mq_open("/myqueue", O_RDONLY);
char buf[128];
unsigned int prio;
mq_receive(mq, buf, 128, &prio);
printf("Сообщение: %s, приоритет: %u\n", buf, prio);
mq_close(mq);
mq_unlink("/myqueue");
return 0;
}
Линкуйте с -lrt на старых системах. Лимиты очереди смотрите в /proc/sys/fs/mqueue/.
POSIX-семафор (именованный)
#include <semaphore.h>
#include <fcntl.h>
#include <stdio.h>
int main(void) {
sem_t *s = sem_open("/mysem", O_CREAT, 0644, 1);
sem_wait(s);
/* критическая секция */
printf("critical\n");
sem_post(s);
sem_close(s);
return 0;
}
Где это встречается в DevOps
- Сигналы: graceful reload (SIGHUP), останов контейнера (SIGTERM, затем SIGKILL), watchdog-процессы.
- Очереди: локальный обмен между воркерами без сети, когда shared memory + mq проще, чем брокер.
- Семафоры: ограничение параллелизма, координация init-скриптов и sidecar-процессов.
В Kubernetes и systemd вы чаще видите сигналы и cgroup-лимиты, чем сырые System V IPC. Но legacy-приложения, Oracle-стек, старые UNIX-утилиты и часть C/C++ сервисов по-прежнему держат msg/sem/shm. ipcs и ipcrm – must-have в чеклисте «почему не освобождается IPC».
Итог
Сигналы управляют жизненным циклом процесса, очереди передают типизированные куски данных, семафоры синхронизируют доступ. System V – массивы, ключи, SEM_UNDO; POSIX – имена, проще API, futex. Для углубления смотрите исходники ядра: signal.c, mqueue.c, sem.c.

