Instrukcja do laboratorium Systemów Operacyjnych (semestr drugi)

w

Ć iczenie trzecie

Temat: Potoki i ł c

ą za nazwane w Linuksie.

Opracowanie:

mgr inż. Arkadiusz Chrobot

Wprowadzenie

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

Sytuacja

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

• Funkcja mkfifo() - tworzy

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

a w drugim za pomoc

ą

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