Какие основные механизмы межпроцессного взаимодействия (IPC) существуют в Linux?

«Какие основные механизмы межпроцессного взаимодействия (IPC) существуют в Linux?» — вопрос из категории Операционные системы, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Основные механизмы IPC:

  1. Каналы (Pipes)

    • Анонимные каналы: Однонаправленный канал данных, обычно используется для связи между родительским и дочерним процессами. Создается системным вызовом pipe().
    • Именованные каналы (FIFO): Канал, представленный в виде файла в файловой системе. Позволяет общаться несвязанным процессам.
  2. Сигналы (Signals)

    • Простейший механизм для отправки асинхронных уведомлений процессу о каком-либо событии (например, SIGTERM для запроса на завершение, SIGKILL для принудительного завершения).
  3. Разделяемая память (Shared Memory)

    • Самый быстрый способ IPC. Ядро выделяет область памяти, которую несколько процессов могут отобразить в свои адресные пространства. Требует внешней синхронизации (например, семафоров) для избежания состояния гонки.
  4. Очереди сообщений (Message Queues)

    • Позволяют процессам обмениваться структурированными сообщениями. Ядро обеспечивает хранение и доставку сообщений в порядке их поступления.
  5. Сокеты (Sockets)

    • Наиболее универсальный механизм, позволяющий общаться как процессам на одной машине (Unix Domain Sockets), так и по сети (TCP/IP Sockets). Предоставляют двунаправленный канал связи.

Пример в Python с использованием multiprocessing.Queue:

Модуль multiprocessing в Python предоставляет высокоуровневые абстракции для IPC. Queue под капотом использует каналы и примитивы синхронизации.

from multiprocessing import Process, Queue
import time

def producer(q):
    """Процесс-производитель, который кладет данные в очередь."""
    for i in range(5):
        data = f"Сообщение #{i}"
        q.put(data)
        print(f"Отправлено: {data}")
        time.sleep(0.5)
    q.put(None) # Сигнал об окончании работы

def consumer(q):
    """Процесс-потребитель, который забирает данные из очереди."""" 
    while True:
        data = q.get()
        if data is None:
            break
        print(f"Получено: {data}")

if __name__ == "__main__":
    # Создаем очередь, доступную для обоих процессов
    queue = Queue()

    p1 = Process(target=producer, args=(queue,))
    p2 = Process(target=consumer, args=(queue,))

    p1.start()
    p2.start()

    p1.join()
    p2.join()