Potok (ang. pipe) – jeden z mechanizmówkomunikacji międzyprocesowej umożliwiający wymianę danych pomiędzy dwomaprocesami. Odbywa się to najczęściej poprzez połączeniestandardowego wyjścia jednego procesu zestandardowym wejściem drugiego.
Mechanizm potoku i jego notacja (pionowa linia) zostały wymyślone przezDouglasa McIlroya, jednego z autorów wczesnych powłok systemowych po tym, jak zaobserwował, że w wielu przypadkach wyjście jednego programu stanowiło wejście dla drugiego. Jego pomysł został zaimplementowany w 1973 roku, przezKena Thompsona w systemie operacyjnymUNIX[1]. Mechanizm potoku został następnie dodany w innychsystemach operacyjnych, takich jakDOS,OS/2,Microsoft Windows iBeOS, często z tą samą notacją.
Wuniksowychpowłokach systemowych używa się symbolu „|” (pionowej linii), aby połączyć dwa lub więcej procesów w potok.
Przykład wykorzystania potoków w systemieUNIX:
$ps-a|sort|uniq|grep-vsh
Powyższa konstrukcja zwróci listę uruchomionych procesów (
), posortowaną alfabetycznie (ps-a
), niezawierającą powtórzeń (sort
), oraz bez linii zawierających wzorzec sh (uniq
).grep-vsh
Do stworzenia nienazwanego potoku służywywołanie systemowe
. Prototyp funkcji bibliotecznej znajduje się w pliku nagłówkowymunistd.h i ma następującą postać:pipe()
intpipe(intfields[2]);
Funkcja
umieszcza dwa nowe deskryptory plików w tablicypipe()
(fields[]
–deskryptor pliku tylko do odczytu,fields[0]
– deskryptor pliku tylko do zapisu) i zwraca 0 w przypadku powodzenia lub -1 w przypadku błędu.fields[1]
Funkcja
często używana jest w połączeniu z funkcjąpipe()
w celu zapewnienia komunikacji między procesem macierzystym oraz jego procesami potomnymi.fork()
Przykład poniżej implementujekorektor pisowni dla zasobówsieciowych wskazywanych przezURL. Znak „\” służy umieszczeniu wszystkich sześciu linii w jednej linii wiersza poleceń.
curl"https://en.wikipedia.org/wiki/Pipeline_(Unix)"|\sed's/[^a-zA-Z ]/ /g'|\tr'A-Z ''a-z\n'|\grep'[a-z]'|\sort-u|\comm-23-/usr/share/dict/words
Specjalny znak „|” mówi interpreterowipowłoki, żeby to, co pojawia się na wyjściu jednego procesu, przekazał na wejście następnego. Tak więc wyjście komendy curl jest przekazywane na wejście komendy sed i tak dalej.
Wszystkie powszechnie używane powłokiUnix iWindows posiadają specjalną strukturę składniową dla tworzenia potoków. W standardowym użyciu polecenia filtra pisane są w sekwencji, oddzielone znakiem „|” (który, z tego powodu jest często nazywane „znakiem pipe”). Powłoka rozpoczyna proces i tworzy niezbędne połączenia pomiędzy standardowymi strumieniami (uwzględniając pewienbufor).
Z założeniastandardowe strumienie błędów procesów w potoku nie są przez niego przekazywane, lecz łączone i kierowane nakonsolę. Jednakże wiele powłok posiada dodatkową składnię zmieniającą to zachowanie. W powłocecsh, na przykład, używanie „|&” zamiast „|” oznacza, że standardowy strumień błędu powinien także zostać połączony ze standardowym wyjściem i przekazany do następnego procesu.Powłoka Bourne’a także potrafi połączyć standardowy strumień błędów ze standardowym wyjściem (za pomocą 2>&1), jak również przekierować go do innego pliku.
W najpowszechniej używanych prostych potokach powłoka łączy serię podprocesów poprzez potok i wykonuje zewnętrzne komendy w obrębie każdego podprocesu. W efekcie powłoka sama w sobie nie wykonuje żadnego bezpośredniego przetwarzania danych wpływających poprzez potok. Jednakże powłoka może wykonać przetwarzanie bezpośrednio. Konstrukt ten, ogólnie rzecz biorąc, wygląda mniej więcej następująco:
command|whilereadvar1var2...;do# przetwórz każdą linię, używając zmiennych parsowanych do $var1, $var2, etc# (zauważ że to jest podpowłoka: var1, var2 etc nie będą dostępne# po zakończeniu pętli)done
...co jest nazywane z angielskiego „pipemill” (walcownia).
W większości systemów uniksowych, wszystkie procesy potoku są rozpoczynane jednocześnie, z ich strumieniami odpowiednio połączonymi i zarządzanymi przezalgorytm szeregowania wraz z innymi procesami uruchomionymi na maszynie. Istotnym aspektem, odróżniającym potoki uniksowe od innych, jest koncept buforowania: program wysyłający może wyprodukować do 5000bajtów nasekundę, a program odbierający może ich przyjąć jedynie 100 na sekundę, jednak żadne dane nie giną. Zamiast tego, strumień wyjściowy programu wysyłającego jest trzymany w kolejce. Kiedy program odbierający jest gotów odczytać dane, system operacyjny przesyła mu dane z kolejki, następnie usuwa te dane z kolejki. Jeżeli bufor kolejki się zapełni, program wysyłający zostaje zawieszony (zablokowany) aż do momentu kiedy program odbierający ma możliwość odczytać jakąś część danych i zrobić miejsce w buforze. W systemieGNU/Linux rozmiar buforu to 65536 bajtów.
Narzędzia takie jaknetcat isocat mogą połączyć potoki z gniazdami TCP/IP, zgodnie z jedną z zasadfilozofii UNIX głoszącą, że „wszystko jest plikiem”.
Potok nazwany (lub łącze nazwane) jest to rozwinięcie idei potoku, polegające na stworzeniu specjalnego pliku, który ma służyć jako łącznik między procesami. Zapewnia to wygodny mechanizm przekazywania danych pomiędzy niespokrewnionymi ze sobą procesami. Wtedy ten specjalny plik potoku jest „nazwą” potoku w tym sensie, że operacje pisania i czytania wykonane na pliku są w istocie czytaniem z i pisaniem do potoku, a plik potoku służy jako swoisty punkt dostępowy.
WUniksie do tworzenia potoków nazwanych stosuje się programmkfifo lubmknod.
$ mkfifo plik_fifo
$ mknod plik_fifo p
Z poziomu programu można skorzystać z następujących dwóch standardowych funkcji:
#include <sys/types.h>#include <sys/stat.h>int mkfifo(const char *path, mode_t mode);int mknod(const char *path, mode_t mode, dev_t dev);