c Wies law P laczek 15 4 Potoki 4.1 Wprowadzenie Potok (ang. pipe) możnauznaćzaplikspecjalnegotypuktórys lużydoprzechowywania ograniczonej ilości danych i do którego dost ep może si eodbywaćjedyniewtrybie FIFO (ang. first-in first-out element umieszczony w buforze pierwszy również pierwszy opuści bufor). Maksymalna liczba bajtów jak amożnazapisaćwpotoku jest określona sta l a PIPE BUF której definicja znajduje si ewplikunag lówkowym<limits.h> lub <sys/param.h>. Potoki zapewniaj aprostysynchroniczny sposób wymiany danych mi edzy procesami. Dane zapisywane s anajedym końcu potoku aodczytywane na drugim jego końcu przyczymodczytane dane s azpotoku usuwane. System zapewnia synchronizacj e mi edzy procesem zapisuj acym i odczytuj acym. Domyślnie jeśli ten pierwszy spróbuje zapisać dane do pe lnego potoku tozostanieprzezsystem automatycznie zablokowany do czasu gdy potok b edzie w stanie je odebrać. Podobnie proces odczytuj acy który podejmie prób epobraniadanychzpustego potoku zostanie zablokowany do czasu kiedy pojawi asi ejakieśdane. Dozablokowania dojdzie również wtedy gdy potok zostanie otwarty przez jeden proces do odczytu alenie zostanie otwarty przez inny proces do zapisu. Dane można zapisawać do potoku za pomoc afunkcjiwrite aodczytywać zniegoza pomoc afunkcjiread (niebuforowane funkcje wejścia/wyjścia). Pliki w l aczane Prototyp ssize t write(int filedes const void *buf size t nbyte); wartość Liczba zapisanych bajtów 1 Tak Funkcja write podejmuje prób ezapisanianbyte bajtów danych wskazywanych przez parametr buf do pliku określonego deskryptorem filedes. Jeśli funkcja write zakończy si e sukcesem to zwróci liczb erzeczywiściezapisanychbajtów. Pliki w l aczane Prototyp ssize t read(int filedes void *buf size t nbyte); wartość Liczba odczytanych bajtów 1 Tak Funkcja read odczytuje nbyte bajtów danych z pliku o desktryptorze filedes i umieszcza je w miejscu pami eci określonym wskaźnikiem buf. Pozytywniezakończonazwraca liczb e rzeczywiście odczytanych bajtów. W przypadku dojścia do końca pliku zwracana jest wartość 0. ) Co to jest deskryptor pliku? W systemie UNIX z każdym otwartym przez proces plikiem zwi azana jest pewna nieujemna liczba ca lkowita zwana deskryptorem pliku. Deskryptory o numerach 0 1 i 2
c Wies law P laczek 16 zwi azane s a odpowiednio ze standardowymi strumieniami: wejścia wyjścia i wyjścia b l edów (maj a one swoje symboliczne nazwy odpowiednio: STDIN FILENO STDOUT FILENO i STDERR FILENO). Deskryptory s luż adoodwo lywaniasi edoplikówprzezniektórefunkcje systemowe. Deskryptory plików procesu macierzystego s adziedziczoneprzezprocesy potomne. Liczba deskryptorów które mog abyćdost epne procesowi jest ograniczona. W starszych wersjach Uniksa nie mog la ona przekroczyć 20 w nowszych wersjach liczba ta może być znacznie wi eksza (można j asprawdzićprzypomocykomendyulimit -n pow loki bash). Deskryptor pliku można utworzyć np. przy pomocy funkcji systemowej open. Pliki w l aczane <sys/types.h> <sys/stat.h> <fcntl.h> Prototyp int open(const char *path int flags mode t mode); wartość Deskryptor pliku 1 Tak Pomyślnie wykonana funkcja open otwiera plik i zwraca jego deskryptor. Parametry: path ścieżkowa nazwa pliku flags opcje mode prawa dost epu do pliku (stosuje si ezapiswsystemieósemkowym) np. rw-r--r--! wsystemiebinarnym:110100100! w systemie ósemkowym: 0644 Opcje flags (ważniejsze): O RDONLY otwórz plik do czytania O WRONLY otwórz plik do pisania O RDWR otwórz plik do czytania i pisania O CREAT jeśli plik nie istnieje to stwórz go O EXCL przy równocześnie ustawionej fladze O CREAT przekaż b l ad jeśli plik już istnieje O TRUNC jeśli plik istnieje zmniejsz jego d lugość do zera (obetnij go) O APPEND otwórz plik w trybie dopisywania na jego końcu. Opcje można l aczyć przy pomocy sumy bitowej np. O WRONLY O CREAT O TRUNC. Deskryptor przypisany do pliku można zwolnić używaj ac funkcji systemowej close. Pliki w l aczane Prototyp int close(int filedes); Pomyślnie zakończona funkcja close zamyka plik tzn. zwalnia używany przez niego deskryptor. Dzi eki temu deskryptor ten może być użyty ponownie jeszcze przed zakończeniem wykonywania procesu. W chwili zakończenia wykonywania procesu wszystkie używane przez ten proces pliki s aautomatyczniezamykane. Dodobregostyluprogramowania należy jednak jawne zamykanie plików które nie s ajużpotrzebne(jakwiadomo
c Wies law P laczek 17 porz adek w programie jest nie tylko kwesti aestetykialecz esto pozwala unikn ać różnych problemów szczególnie przy dalszym rozwoju programu). Funkcj e close można stosować również do deskryptorów o numerach 0 1 i 2 tzn. standardowych strumieni WE/WY. Plik można usun ać przy pomocy funkcji systemowej unlink. Pliki w l aczane Prototyp int unlink(const char *path); Funkcja unlink pomyślniezakończonausuwadowi azanie do pliku o nazwie ścieżkowej path zkataloguorazzmniejszao1licznikdowi azań do tego pliku przechowywany w i-w eźle (ang. i-node) jeśli licznik ten przyjmie wartość 0 to plik zostanie usuni ety. 4.2 Potoki nienazwane Potoki nienazwane mog a l aczyć tylko procesy pokrewne np. macierzysty i potomny dwóch braci dziadka i wnuka itd. Do ich tworzenia s luży funkcja systemowa pipe. Pliki w l aczane Prototyp int pipe(int filedes[2]); W przypadku poprawnego wykonania funkcja pipe zwraca dwa deskryptory plików: filedes[0] i filedes[1] któreodnosz asi edodwóchstrumienidanych. Wobecnych wersjach systemu UNIX funkcja pipe nierzadko wyst epuje w dwóch odmianach. Jedna znichs lużydotworzeniapotoków jednokierunkowych (pó ldupleks) a druga do tworzenia potoków dwukierunkowych (pe lny dupleks). To która z nich jest wywo lywana domyślnie zależy od ustawień systemowych najlepiej sprawdzić to w man pipe. Wpe lnym dupleksie plik filedes[0] s luży do zapisu danych a filedes[1] do ich odczytu i odwrotnie. Natomiast w konfiguracji pó ldupleksowej plik filedes[1] jest zawsze używany do zapisu a filedes[0] zawsze do odczytu próba użycia ich na odwrót kończy si eb l edem. Linux stosuje rozwi azanie pó ldupleksowe. Od wersji j adra o numerze 2.6.27 w Linuksie dost epna jest również specyficzna dla tego systemu funkcja pipe2 szczegó lymożnaznaleśćwman 2 pipe.! Uwaga: Proces powinien zamykać (najlepiej na samym pocz atku) koniec potoku którego nie b edzie używa l (tzn. zwalniać odpowiedni desktryptor funkcj a close) nie jest to konieczne ale może uchronić przed ewentualnymi b l edami!
c Wies law P laczek 18 ĆWICZENIE 4: Producent Konsument: Potoki Nienazwane Przy pomocypotoków nienazwanych systemu UNIX zaimplementować problem Producenta i konsumenta. Dlazademonstrowaniażeniedosz lodoutratyanizwielokrotnienia towaru niechproducent pobiera surowiec (np. porcje bajtów) z pliku tekstowego iwstawiagojakotowar do potoku akonsument niech umieszcza pobrany z potoku towar w innym pliku tekstowym (porcje danych Producenta i Konsumenta nie musz abyć równe). Po zakończeniu dzia lania programów (wyczerpaniu zasobów surowca ) oba pliki tekstowe powinny być identyczne (można to sprawdzić poleceniem di -s którenajlepiej umieścić w pliku Makefile po poleceniu uruchomienia programu). Oba procesy niech drukuj aodpowiedniekomunikatynaekraniewtymtowar któryprzesy laj a. Do zasymulowania różnych szybkości dzia lania programów użyć funkcji sleep np.zlosowymczasem usypiania. Do czytania/pisania danych z/do pliku tekstowego jak również wypisywania ich na ekran użyć funkcji read i write.
c Wies law P laczek 19 4.3 Potoki nazwane (potoki FIFO) Drugi rodzaj potoków wyst epuj acych w systemie UNIX stanowi a potoki nazwane (określane także mianem potoków FIFO). Różni asi eoneodpotokównienazwanychg lównie tym że towarzysz aimwpisywwykazachplikówodpowiednichkatalogów.zatemwprogramach mog abyćtraktowanejakzwyk lepliki. Dzi eki temu potoki FIFO mog a l aczyć niezależne procesy a nie tylko pokrewne jak w przypadku potoków nienazwanych. Dodatkowo potoki FIFO można tworzyć nie tylko z poziomu programu ale również z poziomu pow loki (z linii poleceń). Dzi eki temu potoków FIFO można latwo używać w programach pisanych nie tylko w j ezykach C/C++ ale w dowolnych j ezykach które posiadaj aoperacje czytania/pisania w plikach. Do tworzenia potoków FIFO zliniikomends lużypoleceniemkfifo 3. Sk ladnia tego polecenia jest nast epuj aca: mkfifo [-m mode] file name gdzie file name jest nazw a pliku specjalnego FIFO któryb edzie używany jako potok FIFO a(opcjonalny)mode oznacza prawa dost epu (jak dla zwyk lego pliku np. 644). Plik specjalny FIFO wwykaziezawartościkatalogu(komendals -l) jestoznaczonyliter a p (od pipe) wpierwszejkolumnieatrybutówpliku. Zpoziomuprogramupotoki FIFO można tworzyć przy pomocy funkcji bibliotecznej mkfifo 4. Pliki w l aczane <sys/types.h> <sys/stat.h.> Prototyp int mkfifo(const char *path mode t mode); Funkcja mkfifo tworzy potok FIFO onazwieścieżkowejpath iprawachdost epu określonych parametrem mode wsystemieósemkowymnp.0644. ĆWICZENIE 5: Producent Konsument: Potoki Nazwane Przy pomocy potoków nazwanych systemu UNIX zaimplementować problem Producenta i Konsumenta z ćwiczenia 4. (a) Utworzyć potok FIFO z poziomu programu a nast epnie uruchomić procesy Producenta i Konsumenta wtymsamymprogramie(wprocesiemacierzystymipotomnym lub w dwóch potomnych). (b) Sprawdzić że potoki FIFO dzia laj a dla niezależnych procesów przez utworzenie potoku FIFO z linii komend oraz uruchomienie procesów Producenta i Konsumenta niezależnie z poziomu pow loki np. w różnych terminalach można użyć polecenia: xterm -hold -title nazwa okna -e nazwa programu & dla każdego z tych procesów w pliku Makefile (jak też tworzenie/usuwanie potoku). 3 Istnieje również bardziej ogólne polecenie o nazwie mknod do tworzenia tzw. plików specjalnych w tym m.in. potoków FIFO szczegó ly można znaleźć w man mknod. 4 Istnieje także funkja systemowa mknod odpowiednik polecenia mknod (patrz: man 2 mknod).