Instrukcja do laboratorium Systemów Operacyjnych (semestr drugi)
w
Ć iczenie trzecie
Temat: Potoki i ł c
ą za nazwane w Linuksie.
Opracowanie:
mgr inż. Arkadiusz Chrobot
1. Komunikacja z wykorzystaniem strumieni W systemach uniksowych istnieje możliwość utworzenia nowego procesu realizuj cego
ą
wybrane
polecenie
powłoki
i
stworzenia
dla
niego
cza
łą
komunikacyjnego za pomocą tyko jednego wywołania funkcji. Tą funkcją jest funkcja popen(). Łącze utworzone przy jej pomocy jest jednokierunkowe, tzn.
proces wywo uj
ł
cy
ą
mo e
ż
do niego pisać lub z niego czyta ,
ć ale nigdy te dwie
operacje nie są dost pne
ę
jednocze nie
ś
dla tego samego
cza.
łą
Łącze nale y
ż
zamykać za pomocą funkcji pclose(). Jest ono wi zane ą
ze standardowym
wej ciem
ś
lub wyjściem polecenia, w zale no
ż
ci
ś
od rodzaju operacji, czyli
domy lnie „zast
ś
puje” klawiatur
ę
lub ekran.
ę
2. Potoki
Inną formą komunikacji jednokierunkowej są potoki ( cza łą
nienazwane), które
zwykle
służą
do
wymiany
informacji
między
dwoma
spokrewnionymi
procesami. Choć istnieje mo liwo
ż
ść u ywania
ż
potoku tylko w obr bie
ę
jednego
procesu, to nie jest to rozwiązanie, które stosuje się w praktyce. Potok tworzony jest w przestrzeni jądra, ale poprzez wywo anie ł
funkcji pipe() w przestrzeni
u ytkownika
ż
,
a
dostęp
do
niego
odbywa
się
przy
pomocy
funkcji
umo liwiaj
ż
cych
ą
niskopoziomowe operacje na plikach – read() i write(). Ma on skończoną
pojemno
,
ść
której
wielość
zależy
od
konfiguracji
systemu.
W nowszych wersjach Linuksa (od 2.6.11) wynosi ona 64KiB. Dla utworzonego potoku mo na
ż
ustawić znacznik O_NDELAY (O_NONBLOCK), który powoduje, że
program
nie
będzie
przechodził
w
stan
oczekiwania
w okre lonych
ś
sytuacjach, zwi zanych z obs
ą
ug
ł
potoku (szczegó
ą
y w
ł
nast pnym punkcie).
ę
3. Łącza nazwane, czyli kolejki FIFO
Kolejka jest podobna w działaniu do potoku, ale w przeciwieństwie do niego ma nazw ,
ę a wi c
ę
mogą z niej korzystać procesy niespokrewnione. Kolejki FIFO
pojawi y
ł się w systemach uniksowych zgodnych ze wersją o nazwie System V
(w a
ł
ciwie
ś
to istnia y
ł
już od System III). Pierwotnie tworzono je za pomocą funkcji mknod(), ale obecnie istnieje wygodniejsza w użyciu funkcja mkfifo().
Aby skorzystać z tak utworzonego łącza nazwanego nale y ż go otworzyć albo do
zapisu, albo do odczytu (to samo ograniczenie co w przypadku potoku).
Dodatkowo
można
zastosować
flagę
O_NDELAY
lub
tożsamą
jej
flagę
O_NONBLOCK. Powoduje to, że proces nie będzie czekał na zakończenie pewnych operacji związanych z obsługą kolejki. Dok adniej ł
objaśnia to poniższa
tabela:
2
Nie ustawiono znacznika Ustawiono O_NDELAY lub O_NDELAY lub
O_NONBLOCK
O_NONBLOCK
Otwarto kolejkę tylko do Oczekiwanie,
aż
proces Natychmiastowy
powrót
czytania, aden
ż
proces nie otworzy
kolejkę
do bez sygnalizowania błędu.
otworzył jej do pisania.
pisania.
Otwarto kolejkę tylko do Oczekiwanie,
aż
proces Natychmiastowy
powrót
pisania, żaden proces nie otworzy kolejkę FIFO do z sygnalizacją b du
łę
otworzył jej do czytania.
czytania.
w errno
(umieszczenie
sta ej ENXIO).
ł
Próba
czytania
danych Oczekiwanie, aż pojawią Natychmiastowy powrót,
z kolejki,
jeśli
nie
ma się dane lub nie b dzie
ę
wartość
funkcji
jest
w niej danych.
ona otwarta do pisania równa zero.
dla żadnego procesu. Jeśli
żaden proces nie otworzy
kolejki do pisania funkcja
zwraca
wartość
zero,
w przeciwnym
wypadku
liczb oczytanych bajtów.
ę
Próba
zapisania
do Oczekiwanie,
aż
będzie Jak wy ej.
ż
zape nionego
ł
cza FIFO.
łą
miejsce
do
zapisania
nowych danych.
Powy sza
ż
tabela odnosi się także do potoków. Można również wyodrębnić kilka regu , którym podlega pisanie i czytanie do kolejek i potoków: ł
• Jeśli proces
da
żą
przeczytania mniejszej porcji danych niż wynosi bie ca
żą
zawartość medium, to b dzie
ę
pobrane dokładnie tyle danych, ile za
dano.
żą
Reszta danych nie ulega zniszczeniu i mo e ż być odczytana przy nast pnej
ę
operacji czytania.
• Jeśli proces będzie usi owa
ł
ł odczytać więcej danych niż znajduje się
w medium, to odczytanych i tak zostanie tylko tyle danych, ile jest w potoku lub kolejce.
• Jeśli proces próbuje czytać z medium, które nie zosta o ł
przez żaden inny
proces otwarte do pisania, to wynikiem funkcji read() b dzie ę
zero.
W przypadku kiedy ustawiony jest znacznik O_NDELAY nie mo na ż
stwierdzi , czy medium by
ć
o puste, czy nie zosta
ł
o otwarte do zapisu.
ł
• Zapis danych jest operacją niepodzielną, o ile proces zapisuje dane do medium porcjami mniejszymi od jego pojemności, 3
• Jeśli proces próbuje zapisywać do medium, które nie zosta o ł otwarte przez
inny proces do odczytu, to otrzyma sygnał SIGPIPE, którego domy lna ś
obs uga polega na zako
ł
czeniu procesu.
ń
Po skorzystaniu z kolejki należy ją usunąć, aby nie zajmowała miejsca na dysku.
4. Opis ważniejszych funkcji
• popen() - funkcja uruchamia polecenie powłoki podane w jej argumentach wywołania oraz tworzy strumień s u
ł
cy
żą
do komunikacji między procesem
wywołanym a wywołującym, który można obs ugiwa ł
ć standardowymi
funkcjami fread() i fwrite(). Szczegóły: man 3 popen.
• fread() - służy do odczytu buforowanego ze strumienia. Szczegóły: man 3 fread.
• fwrite() - służy do zapisu buforowanego do strumienia. Szczegóły: man 3 fwrite.
• Funkcja pclose() - służy do zamykania strumienia stworzonego przez popen(). Szczegóły: man 3 pclose.
• Funkcja pipe() - służy do tworzenia potoku łączącego dwa spokrewnione procesy. Jako argument wywo ania
ł
przyjmuje dwuelementową tablic ,
ę
w której b d
ę ą zapisane deskryptory potoku. Deskryptor zerowy jest do odczytu, a pierwszy do zapisu. Zwykle jest ona wywo ywana ł
przed fork(),
co powoduje, że procesy powsta e
ł
w wyniku podziału odziedziczą tablicę
deskryptorów. Każdy z tych procesów zamyka jeden z deskryptorów, np.
jeśli komunikacja przebiega wed ug
ł
schematu: rodzic -> potomek, to
rodzic zamyka deskryptor do odczytu, a potomek do zapisu. Szczegóły: man 2 pipe
• Funkcja read() - czyta określoną liczbę bajtów z deskryptora bez buforowania. Szczegóły: man 2 read.
• Funkcja write() - zapisuje określoną liczbę bajtów do deskryptora bez buforowania. Szczegóły: man 2 write.
• Funkcja close() – zamyka deskryptor pliku. Do zamykania strumieni służy fclose() lub pclose(). Szczegó y: man 2 close.
ł
4
cze
łą
nazwane o podanej nazwie i atrybutach,
mo e by
ż
zast
ć
piona przez
ą
mknod(). Szczegó y: man 3 mkfifo
ł
• Funkcja open() – otwiera plik (również
cze
łą
nazwane). Możliwe jest dzięki
niej ustalenie trybu otwarcia i ustawienie znaczników. Szczegó y: ł
man
2 open.
• Funkcja fcntl() - służy do manipulacji deskryptorem pliku. Można dzięki niej ustawić flagę O_NDELAY (O_NONBLOCK) dla potoku. Szczegóły: man 2 fcntl.
• Funkcja perror() – wypisuje wiadomość o błędzie zwróconą przez system.
Przykład użycia: if(fork() < 0) perror(”fork:”); Szczegóły: man 3 perror.
• Funkcja unlink() – funkcja ta usuwa z systemu plików nazw , ę która mo e
ż
odnosić się do dowi zania
ą
lub pliku (ostatni przypadek odpowiada operacji usuni cia
ę
pliku). Mo na
ż
ją wykorzystać do automatycznego usuwania
cza nazwanego. Szczegó
łą
y: man 2 unlink.
ł
Zadania:
1. Napisz program, który wywo a
ł
polecenie „sort nazwa.c”, gdzie nazwa.c jest nazwą pliku z kodem źródłowym programu, a następnie odczyta 20 znaków zwróconych przez to polecenie i wyświetli je na ekran.
2. Napisz program, który uruchomi polecenie „wc” i przekaże mu na standardowe wej cie dowolny ci
ś
g znaków.
ą
3. Napisz program, który stworzy potok, i wykorzysta go do przesy ania ł
danych
w obr bie jednego procesu.
ę
4. Napisz program, który stworzy potok i wykorzysta go do komunikacji mi dzy ę
dwoma spokrewnionymi procesami. Zadanie wykonaj dla dwóch przypadków: z ustawion flag
ą
O_NDELAY (O_NONBLOCK) i bez.
ą
5. Napisz program, który podzieli się na dwa procesy komunikuj ce ą
się przy
pomocy potoków. Komunikacja musi być dwukierunkowa.
6. Napisz dwa niezale ne
ż
programy, które będą się komunikowa y
ł
przy pomocy
kolejki FIFO. Zadanie wykonaj w dwóch wariantach, tak jak zadanie 4. Po zako czeniu komunikacji kolejk
ń
nale
ę
y usun
ż
.
ąć
7. Napisz program, w którym komunikacja mi dzy ę
spokrewnionymi procesami
b dzie
ę
odbywa a
ł
się w jednym kierunku za pomocą
cza
łą
nienazwanego,
5
ą
cza nazwanego.
łą
8. Stwórz programy do dialogu mi dzy
ę
dwoma u ytkownikami
ż
w systemie. Do
komunikacji u yj
ż
cza FIFO stworzonego za pomoc
łą
funkcji
ą
mknod.
9. Napisz program, który wygeneruje cztery procesy. Ka dy ż
z tych procesów będzie
się komunikował z następnym za pomocą łącza nienazwanego. Pierwszy proces wy le
ś
przez swoje łącze liczby 1,2,3 i 4. Każdy kolejny zwiększy ka d ż ą z nich
o 1, a ostatni wypisze je na ekranie.
10. Napisz trzy programy komunikuj ce
ą
się przez łącza FIFO. Pierwszy program
b dzie
ę
wysy a
ł ł kolejne liczby parzyste, drugi kolejne liczby nieparzyste, a trzeci b dzie
ę
odbierał te liczby i je sumowa .
ł Wszystkie procesy powinny wy wietla
ś
ć
wyniki pracy na ekranie.
6