← Назад к вопросам
Какие знаешь способы реализации межпроцессного взаимодействия?
2.2 Middle🔥 121 комментариев
#Linux и операционные системы#Многопоточность и синхронизация
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Способы реализации межпроцессного взаимодействия (IPC)
1. Pipes (Конвейеры)
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main() {
int fd[2];
char buffer[100];
// Создаём pipe
pipe(fd); // fd[0] = читаем, fd[1] = пишем
if (fork() == 0) {
// Процесс-потребитель
close(fd[1]); // Закрываем запись
read(fd[0], buffer, sizeof(buffer));
printf("Child received: %s\n", buffer);
close(fd[0]);
} else {
// Процесс-производитель
close(fd[0]); // Закрываем чтение
write(fd[1], "Hello from parent", 17);
close(fd[1]);
wait(NULL);
}
return 0;
}
Характеристики:
- Синхронная коммуникация
- Однонаправленная (unidirectional)
- Работает между процессами-предками и потомками
- Данные хранятся в памяти ядра
2. Named Pipes (FIFO)
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
int main() {
const char* fifo_path = "/tmp/myfifo";
// Создаём named pipe
mkfifo(fifo_path, 0666);
if (fork() == 0) {
// Процесс-производитель
int fd = open(fifo_path, O_WRONLY);
write(fd, "Hello FIFO", 10);
close(fd);
} else {
// Процесс-потребитель
int fd = open(fifo_path, O_RDONLY);
char buffer[50];
read(fd, buffer, sizeof(buffer));
printf("Received: %s\n", buffer);
close(fd);
wait(NULL);
}
unlink(fifo_path); // Удаляем FIFO
return 0;
}
Отличия от обычных pipes:
- Существует в файловой системе (как файл)
- Работает между любыми процессами (не обязательно родитель-потомок)
- Более гибко, но медленнее
3. Sockets (TCP/UDP)
TCP сокет (надёжная доставка):
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
// Сервер
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {};
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
listen(server_fd, 5);
int client = accept(server_fd, NULL, NULL);
char buffer[256];
recv(client, buffer, sizeof(buffer), 0);
printf("Server received: %s\n", buffer);
close(client);
close(server_fd);
UDP сокет (быстрая, ненадёжная доставка):
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr = {};
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
bind(sock, (struct sockaddr*)&addr, sizeof(addr));
char buffer[256];
recv(sock, buffer, sizeof(buffer), 0);
sendto(sock, "Response", 8, 0, (struct sockaddr*)&addr, sizeof(addr));
close(sock);
Когда использовать:
- TCP — когда важна надёжность (web, БД)
- UDP — когда важна скорость (игры, потоки видео)
4. Shared Memory (Общая память)
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
struct Message {
char text[256];
int value;
};
int main() {
// Создаём shared memory сегмент
int shmid = shmget(IPC_PRIVATE, sizeof(Message), IPC_CREAT | 0666);
if (fork() == 0) {
// Процесс-писатель
Message* msg = (Message*)shmat(shmid, NULL, 0);
strcpy(msg->text, "Hello Shared Memory");
msg->value = 42;
shmdt(msg);
} else {
// Процесс-читатель
sleep(1); // Ждём писателя
Message* msg = (Message*)shmat(shmid, NULL, 0);
printf("Read: %s = %d\n", msg->text, msg->value);
shmdt(msg);
shmctl(shmid, IPC_RMID, NULL);
wait(NULL);
}
return 0;
}
Характеристики:
- Очень быстро (память, без копирования)
- Нужна синхронизация (семафоры, мьютексы)
- Сложнее отлаживать
- Требует осторожности с race conditions
5. Message Queues (Очереди сообщений)
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
struct Message {
long mtype; // Тип сообщения (должен быть > 0)
char mtext[256];
};
int main() {
int msgid = msgget(IPC_PRIVATE, IPC_CREAT | 0666);
if (fork() == 0) {
// Отправитель
Message msg;
msg.mtype = 1;
strcpy(msg.mtext, "Hello Queue");
msgsnd(msgid, &msg, sizeof(msg.mtext), 0);
} else {
// Получатель
Message msg;
msgrcv(msgid, &msg, sizeof(msg.mtext), 0, 0);
printf("Received: %s\n", msg.mtext);
msgctl(msgid, IPC_RMID, NULL);
wait(NULL);
}
return 0;
}
Преимущества:
- Асинхронная коммуникация
- Сообщения идентифицируются по типу
- Порядок гарантирован
6. Memory-Mapped Files
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main() {
// Создаём файл
int fd = open("/tmp/mmap_file", O_CREAT | O_RDWR, 0666);
ftruncate(fd, 4096); // Размер 4KB
// Отображаем в память
void* addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (fork() == 0) {
// Писатель
strcpy((char*)addr, "Hello mmap");
} else {
// Читатель
sleep(1);
printf("Read: %s\n", (char*)addr);
wait(NULL);
}
munmap(addr, 4096);
close(fd);
return 0;
}
Когда использовать:
- Обмен большими объёмами данных
- Совместный доступ к файлам
- Low-latency IPC
7. Signals (Сигналы)
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void signal_handler(int sig) {
printf("Received signal %d\n", sig);
}
int main() {
signal(SIGUSR1, signal_handler);
if (fork() == 0) {
sleep(1);
kill(getppid(), SIGUSR1); // Отправляем сигнал родителю
} else {
sleep(2);
printf("Parent done\n");
wait(NULL);
}
return 0;
}
Применение:
- Простые уведомления между процессами
- Обработка ошибок (SIGSEGV, SIGABRT)
- Не для передачи больших данных
8. DBus (для Linux систем)
// Требует libdbus
#include <dbus/dbus.h>
int main() {
DBusConnection* conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
// Отправляем методы, сигналы через DBus
return 0;
}
Когда использовать:
- System-level IPC в Linux
- Интеграция с системными сервисами
- High-level interface
Сравнение методов
| Метод | Скорость | Надёжность | Сложность | Область |
|---|---|---|---|---|
| Pipes | Высокая | Высокая | Низкая | Процессы-потомки |
| Named Pipes | Высокая | Высокая | Средняя | Любые процессы |
| TCP/UDP | Средняя | Переменная | Средняя | Сеть |
| Shared Memory | Очень высокая | Низкая | Высокая | Локальные процессы |
| Message Queues | Высокая | Высокая | Средняя | Асинхронные |
| Memory-Mapped | Очень высокая | Высокая | Средняя | Большие данные |
| Signals | Очень низкая | Низкая | Низкая | Простые события |
| DBus | Средняя | Высокая | Средняя | System services |
Best Practices
1. Выбор метода
// Нужна скорость + большие данные → Shared Memory
// Надёжность + простота → TCP Socket
// Асинхронные сообщения → Message Queue
// Простой сигнал → Signal
2. Синхронизация при shared memory
// ВСЕГДА используй мьютексы/семафоры
struct SharedData {
sem_t sem;
int value;
};
3. Обработка ошибок
if (send(sock, data, size, 0) == -1) {
perror("send failed");
// Обработка ошибки
}
Итоговые выводы
- Pipes — простейший способ (parent-child)
- Named Pipes (FIFO) — для любых процессов
- Sockets (TCP) — стандарт для надёжной коммуникации
- Shared Memory — максимальная производительность
- Message Queues — асинхронная коммуникация
- Memory-Mapped Files — для больших объёмов данных
- Signals — для простых событий
- DBus — система-уровневая коммуникация в Linux