Najprościej, potok jest metodą przekierowywania standardowego wyjścia jednego procesu na standardowe wejście innego. Potoki są najstarszym narzędziem IPC, istnieją od najwcześniejszych wersji systemu operacyjnego UNIX. Są szeroko używane, nawet w linii poleceń powłoki.
Powyższy przykład pokazuje zbiór potoków; przetworzenie wyjścia ls na wejście programu sort, a póżniejsze użycie wyjścia sort jako wejście lp. Dane przemieszczają się w jednokierunkowym potoku, wizualnie od lewej do prawej.
Aczkolwiek z zamiłowaniem używamy potoków w różnych skryptach, rzadko zadajemy sobie pytanie co się dzieje na poziomie jądra.
Kiedy proces tworzy potok, jądro tworzy dwa deskryptory na jego użytek. Jeden umożliwia zapis do potoku, drugi czytanie z niego. Na tym poziomie, potoki są mało użyteczne, gdyż tylko proces tworzący potok może z niego czytać. Oto reprezentacja procesu i jądra po utworzeniu potoku:
Z powyższego rysunku łatwo można dostrzec jak deskryptory są połączone nawzajem. Jeżeli proces wysyła dane poprzez potok ( fd0 ), może je otrzymać z fd1. Jest to bardziej złożony proces, niż widać na rysunku. Gdy proces tworzy potok, a póżniej podczas przekazywania danych informacje przepływają przez jądro. Pod Linuxem, potoki są obecnie prezentowane wewnętrznie jako prawidłowe i-węzły ( inodes ). Oczywiście taki i-węzeł przebywa wewnątrz jądra, nie na jakimś fizycznym systemie plików. Takie podejście otwiera nam ładną, poręczną furtkę We/Wy, o czym przekonamy się póżniej.
Na razie potoki są daleko bezurzyteczne. Po co zadawać sobie trud tworzenia potoku aby porozmawiać ze sobą? Najczęściej proces tworzący potok tworzy ( forkuje ;) proces potomny. Proces potomny odziedzicza po rodzicu wszelkie otwarte deskryptory plików, mamy teraz podstawy aby komunikować się między procesami. Oto uaktualniony diagram:
Widzimy, iż oba procesy mają dostęp do deskryptorów plików, które tworzą potok. Na tym poziomie musimy podjąć krytyczną decyzję: w jakim kierunku będą przesyłane dane? Po wybraniu kierunku procesy zamykają końcówkę potoku, z której nie będą korzystać. Przyjmijmy, że potomek przeprowadza jakąś akcję i wywsyła wynik poprzez potok do rodzica. Oto nasz nowy rysunek:
Konstrukcja potoku jest gotowa! Jedyne co musimy teraz zrobić to użyć potoku. Aby tego dokonać bezpośrednio możemy używać tych samych wywołań systemowych, które istnieją do niskopoziomowego dostępu We/Wy do plików ( pamiętaj, że potoki obecnie prezentowane są jako normalne i-węzły )
Aby wysłać dane do potoku używamy wywołania systemowego write(), natomiast aby odczytać dane musimy posłużyć się wywołaniem read(). Pamiętaj, że niskopoziomowe We/Wy do pliku działa z jego deskryptorem! Jednocześnie musisz sobie zdawać sprawę, że niektóre wywołania systemowe, takie jak lseek(), nie działają z deskryptorami potoków.