← Назад к вопросам

Как работает взаимодействие между процессами в Linux?

3.0 Senior🔥 131 комментариев
#DevOps и инфраструктура#Асинхронность и многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Взаимодействие между процессами (IPC) в Linux

IPC (Inter-Process Communication) — это механизм обмена данными между процессами в Linux. Существует несколько основных методов, каждый со своими преимуществами.

1. Pipes (конвейеры) — простое одностороннее взаимодействие

Пиpe — это буфер в ядре для передачи данных между процессами.

Безымянный pipe (unnamed pipe):

import os
import sys

# Создаем pipe: возвращает два file descriptors
read_fd, write_fd = os.pipe()

pid = os.fork()

if pid == 0:  # Дочерний процесс
    os.close(read_fd)  # Закрываем read конец
    os.write(write_fd, b"Hello from child")
    os.close(write_fd)
    sys.exit(0)
else:  # Родительский процесс
    os.close(write_fd)  # Закрываем write конец
    data = os.read(read_fd, 1024)
    print(f"Received: {data.decode()}")
    os.close(read_fd)
    os.wait()  # Ждем завершения дочернего процесса

Именованный pipe (named pipe / FIFO):

import os
import sys

# Создаем FIFO
fifo_path = '/tmp/my_fifo'
if os.path.exists(fifo_path):
    os.unlink(fifo_path)

os.mkfifo(fifo_path)

# Процесс 1 (writer)
with open(fifo_path, 'w') as fifo:
    fifo.write("Data from process 1")

# Процесс 2 (reader) — в отдельном терминале
with open(fifo_path, 'r') as fifo:
    data = fifo.read()
    print(f"Received: {data}")

2. Signals (сигналы) — асинхронное уведомление

Сигналы — это способ отправить простое уведомление между процессами.

import signal
import os
import time

def signal_handler(signum, frame):
    print(f"Received signal {signum}")
    if signum == signal.SIGUSR1:
        print("Custom signal received")

# Регистрируем обработчик
signal.signal(signal.SIGUSR1, signal_handler)

pid = os.fork()

if pid == 0:  # Дочерний процесс
    time.sleep(2)
    os.kill(os.getppid(), signal.SIGUSR1)  # Отправляем сигнал родителю
    sys.exit(0)
else:  # Родительский процесс
    print(f"Child PID: {pid}")
    time.sleep(5)  # Ждем сигнала
    os.wait()

Основные сигналы:

  • SIGTERM (15) — graceful shutdown
  • SIGKILL (9) — force kill (нельзя перехватить)
  • SIGUSR1/SIGUSR2 — кастомные сигналы
  • SIGCHLD — уведомление о завершении дочернего процесса

3. Shared Memory (общая память) — быстрый обмен большими данными

import os
import sys
import mmap
import struct

# Размер общей памяти
SHM_SIZE = 1024
SHM_KEY = b'myshm'

pid = os.fork()

if pid == 0:  # Дочерний процесс (writer)
    # Создаем файл для shared memory
    fd = os.open('/tmp/shm_file', os.O_CREAT | os.O_RDWR, 0o666)
    os.write(fd, b'\0' * SHM_SIZE)
    
    with os.fdopen(fd, 'r+b') as f:
        with mmap.mmap(f.fileno(), SHM_SIZE) as shm:
            # Пишем структурированные данные
            data = struct.pack('I', 42)  # unsigned int
            shm.write(data)
            shm.flush()
            print("Data written to shared memory")
    
    sys.exit(0)
else:  # Родительский процесс (reader)
    time.sleep(0.5)  # Даем время дочернему процессу
    
    with open('/tmp/shm_file', 'r+b') as f:
        with mmap.mmap(f.fileno(), SHM_SIZE) as shm:
            data = shm[:4]
            value = struct.unpack('I', data)[0]
            print(f"Read from shared memory: {value}")
    
    os.wait()
    os.unlink('/tmp/shm_file')

4. Message Queues (очереди сообщений) — надежная доставка

import posix_ipc
import os

# Создаем очередь сообщений
queue = posix_ipc.MessageQueue('/myqueue', flags=os.O_CREAT)

pid = os.fork()

if pid == 0:  # Дочерний процесс (sender)
    queue.send(b"Message 1", priority=1)
    queue.send(b"Message 2", priority=2)
    print("Messages sent")
    sys.exit(0)
else:  # Родительский процесс (receiver)
    msg1, priority1 = queue.receive()
    msg2, priority2 = queue.receive()
    
    print(f"Received: {msg1}, priority: {priority1}")
    print(f"Received: {msg2}, priority: {priority2}")
    
    queue.close()
    queue.unlink()
    os.wait()

5. Sockets (сокеты) — сетевое взаимодействие

Unix domain sockets (для локального взаимодействия):

import socket
import os

socket_path = '/tmp/my_socket.sock'

if os.path.exists(socket_path):
    os.remove(socket_path)

# Server
server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server_socket.bind(socket_path)
server_socket.listen(1)

pid = os.fork()

if pid == 0:  # Client
    time.sleep(0.5)
    client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    client.connect(socket_path)
    client.send(b"Hello Server")
    client.close()
    sys.exit(0)
else:  # Server
    connection, _ = server_socket.accept()
    data = connection.recv(1024)
    print(f"Received: {data.decode()}")
    connection.close()
    server_socket.close()
    os.wait()
    os.remove(socket_path)

6. Сравнение методов IPC

МетодСкоростьНадежностьСлучай использования
PipeБыстроНизкаяПростой data flow
SignalsОчень быстроНизкаяУведомления
Shared MemoryОчень быстроСредняяБольшие данные
Message QueueМедленноВысокаяКритичные данные
SocketsМедленноСредняяСетевое взаимодействие

7. Практический пример — producer/consumer с Queue

from multiprocessing import Queue, Process

def producer(queue):
    for i in range(5):
        queue.put(f"Item {i}")
        print(f"Produced: Item {i}")

def consumer(queue):
    while True:
        item = queue.get()
        if item is None:  # Signal to stop
            break
        print(f"Consumed: {item}")

if __name__ == '__main__':
    queue = Queue()
    
    p1 = Process(target=producer, args=(queue,))
    p2 = Process(target=consumer, args=(queue,))
    
    p1.start()
    p2.start()
    
    p1.join()
    queue.put(None)  # Stop signal
    p2.join()

Итоговая схема

Выбор метода зависит от требований:

  • Простой обмен → Pipes
  • Быстрый обмен большими данными → Shared Memory
  • Надежная доставка → Message Queues
  • Сетевое взаимодействие → Sockets
  • Асинхронные уведомления → Signals

В современных приложениях часто используют multiprocessing.Queue или message brokers (RabbitMQ, Redis) вместо низкоуровневых механизмов.

Как работает взаимодействие между процессами в Linux? | PrepBro