Введение

Механизм межпроцессного взаимодействия с использованием передачи сообщений, первоначальная реализация для оболочек.

В Unix-подобных компьютерных операционных системах конвейер (pipeline) является механизмом межпроцессного взаимодействия с использованием передачи сообщений. Конвейер представляет собой набор процессов, соединенных своими стандартными потоками, так что текстовый вывод каждого процесса (stdout) передается непосредственно в качестве ввода (stdin) следующему. Второй процесс запускается, пока первый все еще выполняется, и они выполняются одновременно. Концепция конвейеров была предложена Дугласом МакИлроем в Bell Labs, родине Unix, во время разработки Unix, формируя философию инструментария. Он назван по аналогии с физическим трубопроводом. Ключевой особенностью этих конвейеров является их "скрытие внутренней реализации" (Ritchie & Thompson, 1974). Это, в свою очередь, обеспечивает большую ясность и простоту системы. В данной статье рассматриваются анонимные конвейеры, где данные, записанные одним процессом, буферизуются операционной системой до тех пор, пока они не будут прочитаны следующим процессом, и этот однонаправленный канал исчезает после завершения процессов. Это отличается от именованных конвейеров, где сообщения передаются в или из конвейера, который получает имя, становясь файлом, и сохраняется после завершения процессов. Стандартный синтаксис оболочки для анонимных конвейеров – перечисление нескольких команд, разделенных вертикальными чертами ("конвейеры" в общепринятой терминологии Unix):

command1 | command2 | command3

Например, чтобы перечислить файлы в текущем каталоге, оставить только строки вывода, содержащие определенную строку, и просмотреть результат на прокручиваемой странице, пользователь вводит следующее в командную строку терминала:

ls -l | grep key | less

Команда ls -l выполняется как процесс, вывод (stdout) которого передается на ввод (stdin) процесса grep key; и аналогично для процесса less. Каждый процесс принимает ввод от предыдущего процесса и выдает вывод следующему процессу через стандартные потоки. Каждая вертикальная черта указывает оболочке соединить стандартный вывод команды слева со стандартным вводом команды справа с помощью механизма межпроцессного взаимодействия, называемого (анонимным) конвейером, реализованным в операционной системе. Конвейеры однонаправленные; данные передаются по конвейеру слева направо.

Трубопроводы в интерфейсах командной строки

Все широко используемые оболочки Unix имеют специальную синтаксическую конструкцию для создания конвейеров. Во всех случаях команды записываются последовательно, разделенные символом вертикальной черты ASCII | (который по этой причине часто называют "символом конвейера"). Оболочка запускает процессы и организует необходимые соединения между их стандартными потоками (включая некоторый объем буферной памяти).

Поток ошибок

По умолчанию стандартные потоки ошибок ("stderr") процессов в конвейере не передаются по каналу; вместо этого они объединяются и направляются в консоль. Однако многие оболочки имеют дополнительный синтаксис для изменения этого поведения. Например, в оболочке csh использование `|&` вместо `|` указывает, что стандартный поток ошибок также должен быть объединен со стандартным выходом и передан следующему процессу. В оболочке Bash также можно объединить стандартную ошибку с помощью `|&` начиная с версии 4.0 или используя `2>&1`, а также перенаправить её в другой файл.

Создание трубопроводов программируемым способом

Трубопроводы могут быть созданы программно. Системный вызов Unix `pipe` просит операционную систему создать новый анонимный объект канала. В результате в процессе создаются два новых открытых файловых дескриптора: конец канала, предназначенный только для чтения, и конец, предназначенный только для записи. Концы канала выглядят как обычные анонимные файловые дескрипторы, за исключением того, что в них нельзя перемещаться по файлу. Чтобы избежать взаимных блокировок и использовать возможности параллелизма, процесс Unix с одним или несколькими новыми каналами обычно вызывает `fork` для создания новых процессов. Каждый процесс затем закрывает те концы канала, которые ему не нужны, прежде чем начать передавать или принимать данные. В качестве альтернативы, процесс может создавать новые потоки и использовать канал для обмена данными между ними. Именованные каналы также могут быть созданы с помощью `mkfifo` или `mknod`, а затем представлены программам как входной или выходной файл при их запуске. Они позволяют создавать многоканальные соединения и особенно эффективны в сочетании с перенаправлением стандартного потока ошибок или с командой `tee`.

Реализация

В большинстве Unix-подобных систем все процессы конвейера запускаются одновременно, с правильно соединенными потоками, и управляются планировщиком совместно со всеми остальными процессами, выполняющимися в системе. Важной особенностью, отличающей Unix-каналы от других реализаций каналов, является концепция буферизации: например, отправляющая программа может генерировать 5000 байт в секунду, а принимающая программа может обрабатывать только 100 байт в секунду, но при этом данные не теряются. Вместо этого вывод отправляющей программы сохраняется в буфере. Когда принимающая программа готова к чтению данных, следующая программа в конвейере считывает данные из буфера. Если буфер заполнен, отправляющая программа приостанавливается (блокируется) до тех пор, пока получатель не удалит хотя бы часть данных из буфера. В Linux размер буфера составляет 65 536 байт (64 КиБ). Для обеспечения больших буферов при необходимости доступен сторонний фильтр с открытым исходным кодом под названием bfr.

Сетевые трубы

Такие инструменты, как netcat и socat, могут соединять каналы с TCP/IP-сокетами.

История

Концепция конвейера была изобретена Дугласом Макилроем и впервые описана в справочных страницах Unix версии 3. Макилрой заметил, что в большинстве случаев командные оболочки передавали выходные данные одной программы в качестве входных данных для другой. Его идеи были реализованы в 1973 году, когда ("за одну лихорадочную ночь", как писал Макилрой) Кен Томпсон добавил системный вызов `pipe` и сами конвейеры в оболочку и несколько утилит в Unix версии 3. "На следующий день", – продолжал Макилрой, – "наблюдалась незабываемая вакханалия однострочников, когда все с энтузиазмом включились в процесс соединения программ". Макилрой также отдает должное Томпсону за обозначение `|`, которое значительно упростило описание синтаксиса конвейеров в версии 4. Хотя конвейеры Unix и были разработаны независимо, они связаны с и предшествовали "коммуникационным файлам", разработанным Кеном Локнером в 1960-х годах для системы совместного использования времени в Дартмуте. В концепции Communicating Sequential Processes (CSP) Тони Хоара конвейеры Макилроя получили дальнейшее развитие. Робот на значке Apple Automator, который также использует концепцию конвейера для объединения повторяющихся команд, держит трубу в знак уважения к оригинальной концепции Unix.

Другие операционные системы

Эта особенность Unix была перенята другими операционными системами, такими как MS DOS и пакет CMS Pipelines в средах VM/CMS и MVS, и со временем стала известна как шаблон проектирования "конвейеры и фильтры" в разработке программного обеспечения.