Межпроцессное взаимодействие (IPC)

Очереди сообщений

Реализованы как специальный файл. В адресном пространстве ядра ведётся таблица всех очередей. Каждое сообщение имеет тип (целое положительное число) и текст.

struct msgbuf {
    long mtype;           /* тип сообщения (> 0) */
    char mtext[MSGMAX];   /* текст (обычно до 2048 байт) */
};

Системные вызовы

int msgget(key_t key, int flag);        /* создать/открыть */
int msgsnd(int fd, const void *buf, size_t len, int flag);  /* отправить */
ssize_t msgrcv(int fd, void *buf, size_t len, long mtype, int flag); /* получить */
int msgctl(int fd, int cmd, struct msqid_ds *buf); /* управление */

Параметр mtype в msgrcv():

  • 0 — принять самое старое сообщение любого типа.
  • > 0 — принять сообщение указанного типа.
  • < 0 — принять сообщение с типом ≤ |mtype|.
/* Создать очередь с ключом 15 */
int fd = msgget(15, IPC_CREAT | 0644);

/* Отправить */
msg.mtype = 1;
strcpy(msg.mtext, "Hello");
msgsnd(fd, &msg, strlen(msg.mtext) + 1, 0);

/* Получить */
msgrcv(fd, &msg, 2048, 0, 0);

/* Удалить */
msgctl(fd, IPC_RMID, NULL);
ipcs -q           # показать очереди
ipcrm -q <id>    # удалить по id
ipcrm -Q <key>   # удалить по ключу

Семафоры

Переменная с целым неотрицательным значением для синхронизации процессов. В UNIX семафоры организованы в наборы (массивы).

Атрибуты каждого семафора:

  • semval — текущее значение.
  • sempid — PID процесса, последним изменившего.
  • semncnt — число процессов, ожидающих увеличения.
  • semzcnt — число процессов, ожидающих обнуления.

Системные вызовы

int semget(key_t key, int nsems, int flag);  /* создать/открыть набор */
int semop(int fd, struct sembuf *ops, size_t nops);  /* операции */
int semctl(int fd, int semnum, int cmd, union semun arg); /* управление */
struct sembuf {
    unsigned short sem_num;  /* номер семафора */
    short sem_op;            /* операция: >0 (V), <0 (P), =0 (ждать нуля) */
    short sem_flg;           /* 0, IPC_NOWAIT, SEM_UNDO */
};
SEM_UNDO — отменить изменения семафора при завершении процесса. Защита от зависания при аварийном завершении.
ipcs -s           # показать семафоры
ipcrm -s <id>    # удалить по id

Разделяемая память

Наиболее быстрый способ IPC. Несколько процессов отображают один сегмент памяти в свои адресные пространства.

Системные вызовы

int shmget(key_t key, size_t size, int flag);   /* создать/открыть */
void *shmat(int fd, const void *addr, int flag); /* присоединить */
int shmdt(const void *addr);                     /* отсоединить */
int shmctl(int fd, int cmd, struct shmid_ds *buf); /* управление */
int fd = shmget(5, 4096, IPC_CREAT | 0644);
char *addr = (char *)shmat(fd, NULL, 0);
strcpy(addr, "Привет из разделяемой памяти!");
shmdt(addr);
shmctl(fd, IPC_RMID, NULL);
Удаление сегмента (IPC_RMID) происходит только после отсоединения всех процессов. Для синхронизации доступа используют семафоры.
ipcs -m           # показать сегменты памяти
ipcrm -m <id>    # удалить

Сравнение механизмов IPC

Механизм Скорость