Сигналы, очереди сообщений и семафоры в Linux: основы IPC для DevOps
Сигналы, очереди сообщений и семафоры в Linux — это три столпа межпроцессного взаимодействия (IPC), унаследованные от UNIX и адаптированные под современные DevOps-задачи. Они управляют процессами, передают данные и синхронизируют доступ к ресурсам, оставаясь незаменимыми для контейнеров, оркестрации и распределенных систем. В этой статье мы разберем их историю, теорию, реализацию в ядре Linux и практические примеры, уделяя особое внимание семафорам System V и POSIX.
История сигналов: эволюция от UNIX к Linux
Сигналы появились в UNIX в 1970-х, созданные Деннисом Ритчи и Кеном Томпсоном для уведомления процессов о событиях (SIGINT, SIGCHLD). UNIX System V (1983) интегрировал их в IPC, а POSIX (1980-е) добавил сигналы реального времени (SIGRTMIN–SIGRTMAX). Линус Торвальдс адаптировал их для Linux в 1991 году, и сегодня доступно более 60 сигналов.
История очередей сообщений: System V и POSIX
Очереди сообщений возникли в UNIX System V (1983) с ключами (key_t) и структурой struct msg_queue
. POSIX-очереди (POSIX.1b, 1993) интегрированы в /dev/mqueue
с приоритетами и уведомлениями, ориентированы на реальное время.
История семафоров: от Дейкстры до Linux
Семафоры изобрел Эдсгер Дейкстра в 1965 году как абстрактный счетчик с операциями P (уменьшение) и V (увеличение) для синхронизации. В UNIX System V (1983) они стали частью IPC для управления доступом между процессами. POSIX (1990-е) ввел именованные и неименованные семафоры в рамках POSIX.1b, улучшив переносимость и поддержку потоков. В Linux оба стандарта сосуществуют: System V для legacy-систем, POSIX для современных приложений.
Теория: сигналы, очереди и семафоры в ядре
Сигналы
- Жизненный цикл: Генерация (
kill
,sigqueue
) → очередьsigpending
→ доставка (get_signal
) → (SIG_DFL
,SIG_IGN
, обработчик). - Реализация:
kernel/signal.c
. - Структуры:
struct signal_struct
вtask_struct
сsigpending
,blocked
,sigqueue
.
Очереди сообщений
System V:
- Хранение: Цепочка
struct msg_msg
вstruct msg_queue
. - Управление:
msgsnd
иmsgrcv
с выбором поmtype
. - Реализация:
ipc/msg.c
.
POSIX:
- Создание:
mq_open("/name", flags)
сstruct mq_attr
(mq_maxmsg
,mq_msgsize
). - Хранение: Кольцевой буфер в
/dev/mqueue
, сообщения с приоритетами 0–31. - Управление:
mq_send(mq, msg, len, prio)
: добавляет сообщение по приоритету.mq_receive(mq, buf, size, &prio)
: извлекает с максимальным приоритетом.mq_notify(mq, &sigev)
: уведомление через сигналы.
- Реализация:
ipc/mqueue.c
.
Семафоры
System V:
- Концепция: массив семафоров (
sem_array
), управление черезsemget
,semctl
,semop
. - Хранение:
struct sem_array
сstruct sem
(semval
,sempid
,semncnt
,semzcnt
). - Реализация:
ipc/sem.c
.
POSIX:
- Концепция: один семафор (
sem_t
) с простым API. - Типы:
- Именованные:
sem_open("/name", O_CREAT, mode, value)
в/dev/shm
. - Неименованные:
sem_init(&sem, pshared, value)
в памяти процесса.
- Именованные:
- Управление:
sem_wait(sem)
: уменьшает, блокирует если 0.sem_post(sem)
: увеличивает, разблокирует.sem_timedwait(sem, &timeout)
: ожидание с таймаутом.
- Реализация:
kernel/futex.c
,glibc
.
Практика для DevOps: примеры
Сигналы
#include <signal.h> #include <stdio.h> void handler(int sig) { printf("Сигнал %d\n", sig); } int main() { signal(SIGUSR1, handler); printf("PID: %d\n", getpid()); while (1) sleep(1); }
Очереди сообщений (POSIX)
Отправитель:
#include <mqueue.h> int main() { 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; }
Получатель:
#include <mqueue.h> #include <stdio.h> int main() { 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; }
Итог
Сигналы, очереди и семафоры — это основа IPC в Linux, соединяющая историю UNIX с задачами 2025 года. Сигналы управляют процессами, очереди передают данные, а семафоры синхронизируют доступ: System V с массивами и SEM_UNDO, POSIX с простотой и futex. Изучайте kernel/signal.c, ipc/mqueue.c и ipc/sem.c.