В некоторых ситуациях разные IPC-механизмы могут демонстрировать существенные различия в производительности. Однако в последующих главах мы воздержимся от сравнений в этом контексте по нескольким причинам:
• производительность IPC-механизма может не оказывать заметного влияния на общую производительность приложения и не быть единственным фактором при выборе средства межпроцессного взаимодействия;
• относительная производительность различных IPC-механизмов может варьироваться в зависимости от реализации UNIX или версии ядра Linux;
• и самое важное: производительность IPC-механизма зависит от того, как именно и в какой среде его используют. Это относится к объему данных, передаваемых в каждой IPC-операции, необходимости переключения контекста процесса при передаче каждой порции данных и общей загруженности системы.
Если производительность IPC играет решающую роль, единственный способ выбрать подходящий механизм — провести измерения в среде, которая соответствует целевой системе. Для этого можно даже написать абстрактный программный слой, инкапсулирующий подробности реализации IPC-механизма, и затем провести тестирование производительности с помощью разных средств межпроцессного взаимодействия.
В этой главе мы кратко рассмотрели различные механизмы, которые могут применяться для синхронизации процессов (и потоков) и их взаимодействия.
Среди средств взаимодействия, доступных в Linux, можно выделить каналы, очереди FIFO, сокеты, очереди сообщений и разделяемую память. Синхронизация в Linux выполняется за счет семафоров и файловых блокировок.
Во многих случаях для выполнения одной и той же задачи можно выбирать из нескольких механизмов взаимодействия и синхронизации. В этой главе мы сравнивали разные методики в различных контекстах, пытаясь выделить те особенности, которые могут повлиять на выбор того или иного механизма.
В следующих главах мы более подробно остановимся на каждом механизме взаимодействия и синхронизации.
43.1. Напишите программу, измеряющую пропускную способность каналов. В качестве аргументов командной строки она должна принимать количество блоков данных, которые нужно послать, и размер каждого такого блока. После создания канала программа делится на два процесса: дочерний, записывающий блоки данных в канал с максимально возможной скоростью, и родительский, считывающий данные блоки. После прочтения всей информации родительский процесс должен вывести время, которое ему для этого понадобилось, а также скорость передачи данных (в байтах в секунду). При измерении пропускной способности используйте разные размеры блоков.
43.2. Повторите предыдущее упражнение для очередей сообщений в System V и POSIX, а также для сокетов UNIX- и интернет-доменов. Примените все эти программы для сравнения относительной производительности различных IPC-механизмов в Linux. Если у вас есть доступ к другим UNIX-системам, выполните аналогичное сравнение и в них.
44. Каналы и очереди FIFO
Эта глава посвящена каналам и очередям FIFO. Каналы являются наиболее старым средством межпроцессного взаимодействия в UNIX-системах; они появились в третьем издании UNIX в начале 1970-х. Этот механизм предоставляет элегантное решение распространенной задачи: имея два процесса, выполняющие две разные программы (команды), нужно сделать так, чтобы командная оболочка направила вывод одного из них в ввод другого. Каналы могут использоваться для передачи данных между родственными процессами (мы проясним значение слова «родственные» чуть позже). Очереди FIFO — одна из вариаций концепции каналов. Их важной особенностью является то, что их можно применять для организации взаимодействия
Любому пользователю командной оболочки встречались команды с применением каналов. Например, команда, представленная ниже, считает количество файлов в каталоге:
$ ls | wc — l
Для выполнения данной команды командная оболочка создает два процесса и выполняет в них соответственно утилиты ls и ws (это делается с помощью вызовов fork() и exec(), описанных в главах 24 и 27). На рис. 44.1 показано, как оба процесса используют канал.
Помимо прочего, рис. 44.1 иллюстрирует то, почему каналы (англ. pipe — «труба») получили такое название. Мы можем рассматривать их как фрагмент трубы, которая позволяет пропускать через себя потоки данных, направляя их от одного процесса к другому.
Рис. 44.1.