Mam dwa proste programy: A
i B
. A
uruchamia się jako pierwszy, a następnie B
pobiera „standardowe wyjście” A
i używa go jako „standardowe wejście”. Załóżmy, że używam systemu operacyjnego GNU / Linux, a najprostszym możliwym sposobem jest:
./A | ./B
Gdybym musiał opisać to polecenie, powiedziałbym, że jest to polecenie, które pobiera dane wejściowe (tj. Odczytuje) od producenta ( A
) i zapisuje je konsumentowi ( B
). Czy to poprawny opis? Czy coś mi brakuje?
pipe
terminology
nihulus
źródło
źródło
Odpowiedzi:
Jedyną rzeczą w twoim pytaniu, która wyróżnia się jako błędna, jest to, że mówisz
W rzeczywistości oba programy byłyby uruchamiane prawie w tym samym czasie. Jeśli nie ma danych wejściowych
B
podczas próby odczytu, będzie blokowany, dopóki nie będzie danych wejściowych do odczytu. Podobnie, jeśli nikt nie odczytuje danych wyjściowychA
, zapisy będą blokowane, dopóki dane wyjściowe nie zostaną odczytane (część zostanie buforowana przez potok).Jedyne, co synchronizuje procesy biorące udział w potoku, to operacje we / wy, tj. Odczyt i zapis w poprzek potoku. Jeśli nie nastąpi pisanie ani czytanie, oba procesy będą działać całkowicie niezależnie od siebie. Jeśli jeden zignoruje odczyt lub zapis drugiego, zignorowany proces zostanie zablokowany i ostatecznie zostanie zabity przez
SIGPIPE
sygnał (w przypadku zapisu) lub otrzyma warunek końca pliku w swoim standardowym strumieniu wejściowym (w przypadku odczytu) po zakończeniu drugiego procesu .Idiomatyczny sposób opisania
A | B
polega na tym, że jest to potok zawierający dwa programy. Wyjście wytworzone na standardowym wyjściu z pierwszego programu jest dostępne do odczytu na standardowym wejściu przez drugi („[wyjście z]A
jest przesyłane do [wejście z]]B
). Powłoka wykonuje wymagane czynności hydrauliczne, aby to umożliwić.Jeśli chcesz użyć słów „konsument” i „producent”, to chyba też jest w porządku.
Fakt, że są to programy napisane w C, nie ma znaczenia. Fakt, że jest to Linux, macOS, OpenBSD lub AIX, nie ma znaczenia.
źródło
mkfifo
do utworzenia nazwanego potoku, a następnie rozpoczęcie B w czytaniu w tle z potoku, a następnie zapisanie do niego A. Jest to jednak wybieranie nitów, ponieważ efekt byłby taki sam.yes | sed 10q
Termin zwykle używany w dokumentacji to „potok”, który składa się z jednego lub więcej poleceń, patrz definicja POSIX. Technicznie rzecz biorąc, są to dwa polecenia, które masz, dwa podprocesy dla powłoki (albo
fork()+exec()
polecenia zewnętrzne lub podpowłoki)Jeśli chodzi o część producent-konsument , rurociąg można opisać za pomocą tego wzoru, ponieważ:
/proc/<pid>/fd
katalog).stdout
a konsumenci czytająstdin
tak, jakby wykonywali pojedyncze polecenie, czyli mogą istnieć bez siebie .Różnica, którą widzę tutaj, polega na tym, że w przeciwieństwie do Producer-Consumer w innych językach, polecenia powłoki używają buforowania i zapisują standardowe wyjście po zapełnieniu bufora, ale nie ma wzmianki, że Producer-Consumer musi przestrzegać tej reguły - tylko czekać, gdy kolejka jest zapełniona lub odrzucić dane (czego innego nie robi potok).
źródło