Programowanie współbieżne i rozproszone/PWR Ćwiczenia 4: Różnice pomiędzy wersjami
Nie podano opisu zmian |
Nie podano opisu zmian |
||
Linia 1: | Linia 1: | ||
== Tematyka laboratorium == | |||
# Łącza nienazwane w systemie Unix: deskryptory plików, tworzenie i zamykanie łączy, duplikowanie łączy, zapis i odczyt z łącza | |||
# Łącza nienazwane jako realizacja komunikacji asynchronicznej | |||
Literatura | == Literatura uzupełniająca == | ||
# M. Rochkind, ''Programowanie w systemie Unix dla zaawansowanych'', rozdz. 6.2 i 6.3 | |||
# W. R. Stevens, ''Programowanie zastowań sieciowych w systemie UNI'', rozdz. 2.3 i 3.4 | |||
# M. J. Bach, ''Budowa systemu operacyjnego UNIX'', rozdz. 7.1 | |||
# ''man'' do poszczególnych funkcji systemowych | |||
== Pliki z programami przykładowymi == | |||
*<tt>Makefile</tt> | |||
*<tt>err.h</tt> plik nagłówkowy biblioteki obsługującej błędy | |||
*<tt>err.c</tt> biblioteka do obsługi błędów | |||
*<tt>parent_pipe.c</tt> program ilustrujący komunikację za pomocą łącza. Współpracuje z <tt>child_pipe</tt> | |||
*<tt>child_pipe.c</tt> program ilustrujący komunikację za pomocą łącza. Współpracuje z <tt>parent_pipe</tt> | |||
*<tt>parent_dup.c</tt> program ilustrujący duplikację łącza | |||
== Scenariusz zajęć == | |||
=== Deskryptory, otwarte pliki | |||
Gdy proces otwiera plik, informacje o tym pliku (m.in.: tryb otwarcia, położenie na dysku, wskaźnik pliku, czyli pozycja w pliku, której będzie dotyczyć kolejna operacja wejścia/wyjścia itp.) są zapisywane w tablicy otwartych plików utrzymywanej przez system operacyjny. W całym systemie jest jedna taka tablica. Z kolei informacja o położeniu danych o pliku w systemowej tablicy plików otwartych (oraz pewne dodatkowe informacje) jest zapamiętywana w tablicy deskryptorów tego procesu, który plik otworzył. Każdy proces utrzymuje tablicę deskryptorów --- jest ona lokalna dla procesu, znajduje się w jego danych systemowych (a więc jest kopiowana przy wykonywaniu funkcji <tt>fork()</tt>). Indeks w tej tablicy to właśnie deskryptor pliku. | |||
; Rysunek | |||
Do otwierania pliku służy funkcja systemowa | |||
:<tt>open</tt>. | |||
W wyniku przekazuje ona deskryptor otwartego pliku lub informacje o błędzie. | |||
; Zadanie | |||
: Przeczytaj stronę ''man'' dotyczącą funkcji <tt>open</tt> | |||
W wyniku otwarcia pliku, tworzy się ''nowa'' pozycja w tablicy otwartych plików. Oznacza to, że jeśli proces dwukrotnie otworzy ten sam plik, to w tablicy otwartych plików będą ''dwie'' różne pozycje dotyczące tego pliku. Proces będzie miał również ''dwa'' różne deskryptory odnoszące się do tego samego pliku. Ponieważ wskaźnik pliku jest pamiętany w systemowej tablicy otwartych plików, więc operacje wejścia/wyjścia wykonywane za pomocą różnych deskryptorów będą od siebie niezależne (wykonanie operacji odczytu za pośrednictwem jednego deskryptora nie ma wpływu na pozycję, z której odczytamy kolejne dane z pliku za pośrednictwem drugiego deskryptora). | |||
; Test wyboru | |||
Przypuśćmy, że proces wykonuje następujący ciąg operacji: | |||
Załóżmy, że w pliku <tt>test.txt</tt> znajdują się po kolei znaki <tt>abcd</tt>. | |||
Zmienne tego procesu mają następujące wartości: | |||
Gdy proces wykonuje funkcję systemową <tt>fork()</tt> tablica deskryptorów jest kopiowana do procesu potomnego. Zatem potomek "dziedziczy" po procesie macierzystym wszystkie otwarte pliki. Co więcej, deskryptory o tych samych wartościach w procesie potomnym i macierzystym odnoszą się do tej samej pozycji w systemowej tablicy otwartych plików. | |||
; Rysunek | |||
Wynika z tego, że rodzic i potomek ''współdzielą'' otwarte pliki, tj. każda operacja wejścia/wyjścia w procesie macierzystym przesuwa wskaźnik pliku i powoduje, że kolejna operacja wejścia/wyjścia w procesie potomnym będzie dotyczyć ''kolejnej'' porcji danych z pliku. | |||
; Test wyboru | |||
Przypuśćmy, że proces wykonuje następujący ciąg operacji: | |||
Załóżmy, że w pliku <tt>test.txt</tt> znajdują się po kolei znaki <tt>abcd</tt>. | |||
Zmienne tego procesu mają następujące wartości: | |||
Wykonanie funkcji systemowej <tt>exec()</tt> nie ma wpływu na postać tablicy deskryptorów.Po wykonaniu funkcji <tt>exec()</tt> proces zachowuje otwarte pliki (choć zapewne nie zna już wartości ich deskryptorów, bo zmienne, które przechowywały te wartości przestały istnieć w chwili wykonania funkcji <tt>exec()</tt>). | |||
Do czytania z pliku służy funkcja systemowa <tt>read</tt>, a do zapisu funkcja systemowa <tt>write</tt>. Funkcje te są ''niepodzielne''. | |||
Oznacza to, że operacje read i/lub write wykonywane na tym samym pliku "jednocześnie" nie będą się przeplatać: druga rozpocznie się po | |||
zakończeniu pierwszej. | |||
; Zadanie | |||
:Przeczytaj man read i man 2 write | |||
<!-- | |||
Współdzielenie deskryptorów jest także możliwe w pojedynczym procesie. | Współdzielenie deskryptorów jest także możliwe w pojedynczym procesie. | ||
Aby stworzyć kopie deskryptora pliku używamy funkcji: | Aby stworzyć kopie deskryptora pliku używamy funkcji: | ||
Linia 111: | Linia 73: | ||
a w wypadku błędu wartość -1. | a w wypadku błędu wartość -1. | ||
* Przeczytaj man dup | * Przeczytaj man dup | ||
=== Łącza nienazwane | |||
==== Zasada działania ==== | |||
==== Tworzenie ==== | |||
==== Zapis ==== | |||
==== Odczyt ==== | |||
==== Zamykanie ==== | |||
=== Przekierowywanie wejścia/wyjścia | |||
== Implementacja czytelników i pisarzy za pomocą łączy == | |||
== Zadanie zaliczeniowe == | |||
Napisz program <tt>pierścień</tt> tworzący ''N'' procesów, z których każdy działa następująco: | |||
# pierwszy z nich w pętli: | |||
## odczytuje ze standardowego wejścia komunikaty co najwyżej 100 znakowe zakończone znakiem końca wiersza | |||
## przesyła ten komunikat za pomocą standardowego deskryptora wyjściowego do łącza, z którego odczyta go drugi proces | |||
## powtarza kroki 1-2 do chwili odczytania pustego komunikatu | |||
# wszystkie z wyjątkiem ostatniego: | |||
## odbierają z łącza od poprzedniego procesu za pomocą standardowego deskryptora wejściowego komunikat | |||
## przesyłają go za pomocą standardowego deskryptora wyjściowego do kolejnego procesu | |||
# ostatni proces przesyła odebierane komunikaty do pierwszego, który wypisuje je na ekranie. | |||
Przy starcie każdego procesu rezerwowane są trzy specjalne deskryptory | Przy starcie każdego procesu rezerwowane są trzy specjalne deskryptory | ||
Linia 261: | Linia 255: | ||
--------- | --------- | ||
--> | --> |
Wersja z 08:10, 13 cze 2006
Tematyka laboratorium
- Łącza nienazwane w systemie Unix: deskryptory plików, tworzenie i zamykanie łączy, duplikowanie łączy, zapis i odczyt z łącza
- Łącza nienazwane jako realizacja komunikacji asynchronicznej
Literatura uzupełniająca
- M. Rochkind, Programowanie w systemie Unix dla zaawansowanych, rozdz. 6.2 i 6.3
- W. R. Stevens, Programowanie zastowań sieciowych w systemie UNI, rozdz. 2.3 i 3.4
- M. J. Bach, Budowa systemu operacyjnego UNIX, rozdz. 7.1
- man do poszczególnych funkcji systemowych
Pliki z programami przykładowymi
- Makefile
- err.h plik nagłówkowy biblioteki obsługującej błędy
- err.c biblioteka do obsługi błędów
- parent_pipe.c program ilustrujący komunikację za pomocą łącza. Współpracuje z child_pipe
- child_pipe.c program ilustrujący komunikację za pomocą łącza. Współpracuje z parent_pipe
- parent_dup.c program ilustrujący duplikację łącza
Scenariusz zajęć
=== Deskryptory, otwarte pliki Gdy proces otwiera plik, informacje o tym pliku (m.in.: tryb otwarcia, położenie na dysku, wskaźnik pliku, czyli pozycja w pliku, której będzie dotyczyć kolejna operacja wejścia/wyjścia itp.) są zapisywane w tablicy otwartych plików utrzymywanej przez system operacyjny. W całym systemie jest jedna taka tablica. Z kolei informacja o położeniu danych o pliku w systemowej tablicy plików otwartych (oraz pewne dodatkowe informacje) jest zapamiętywana w tablicy deskryptorów tego procesu, który plik otworzył. Każdy proces utrzymuje tablicę deskryptorów --- jest ona lokalna dla procesu, znajduje się w jego danych systemowych (a więc jest kopiowana przy wykonywaniu funkcji fork()). Indeks w tej tablicy to właśnie deskryptor pliku.
- Rysunek
Do otwierania pliku służy funkcja systemowa
- open.
W wyniku przekazuje ona deskryptor otwartego pliku lub informacje o błędzie.
- Zadanie
- Przeczytaj stronę man dotyczącą funkcji open
W wyniku otwarcia pliku, tworzy się nowa pozycja w tablicy otwartych plików. Oznacza to, że jeśli proces dwukrotnie otworzy ten sam plik, to w tablicy otwartych plików będą dwie różne pozycje dotyczące tego pliku. Proces będzie miał również dwa różne deskryptory odnoszące się do tego samego pliku. Ponieważ wskaźnik pliku jest pamiętany w systemowej tablicy otwartych plików, więc operacje wejścia/wyjścia wykonywane za pomocą różnych deskryptorów będą od siebie niezależne (wykonanie operacji odczytu za pośrednictwem jednego deskryptora nie ma wpływu na pozycję, z której odczytamy kolejne dane z pliku za pośrednictwem drugiego deskryptora).
- Test wyboru
Przypuśćmy, że proces wykonuje następujący ciąg operacji: Załóżmy, że w pliku test.txt znajdują się po kolei znaki abcd. Zmienne tego procesu mają następujące wartości:
Gdy proces wykonuje funkcję systemową fork() tablica deskryptorów jest kopiowana do procesu potomnego. Zatem potomek "dziedziczy" po procesie macierzystym wszystkie otwarte pliki. Co więcej, deskryptory o tych samych wartościach w procesie potomnym i macierzystym odnoszą się do tej samej pozycji w systemowej tablicy otwartych plików.
- Rysunek
Wynika z tego, że rodzic i potomek współdzielą otwarte pliki, tj. każda operacja wejścia/wyjścia w procesie macierzystym przesuwa wskaźnik pliku i powoduje, że kolejna operacja wejścia/wyjścia w procesie potomnym będzie dotyczyć kolejnej porcji danych z pliku.
- Test wyboru
Przypuśćmy, że proces wykonuje następujący ciąg operacji: Załóżmy, że w pliku test.txt znajdują się po kolei znaki abcd. Zmienne tego procesu mają następujące wartości:
Wykonanie funkcji systemowej exec() nie ma wpływu na postać tablicy deskryptorów.Po wykonaniu funkcji exec() proces zachowuje otwarte pliki (choć zapewne nie zna już wartości ich deskryptorów, bo zmienne, które przechowywały te wartości przestały istnieć w chwili wykonania funkcji exec()).
Do czytania z pliku służy funkcja systemowa read, a do zapisu funkcja systemowa write. Funkcje te są niepodzielne. Oznacza to, że operacje read i/lub write wykonywane na tym samym pliku "jednocześnie" nie będą się przeplatać: druga rozpocznie się po zakończeniu pierwszej.
- Zadanie
- Przeczytaj man read i man 2 write