Programowanie współbieżne i rozproszone/PWR Ćwiczenia 4: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Mengel (dyskusja | edycje)
Nie podano opisu zmian
 
Mengel (dyskusja | edycje)
Nie podano opisu zmian
Linia 1: Linia 1:
<!--
== Tematyka laboratorium ==
Laboratorium 3
# Łą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
  + Rochkind, rozdz. 6.2 i 6.3
# W. R. Stevens, ''Programowanie zastowań sieciowych w systemie UNI'', rozdz. 2.3 i 3.4
  + Stevens, rozdz. 2.3 i 3.4
# M. J. Bach, ''Budowa systemu operacyjnego UNIX'', rozdz. 7.1
  + Bach, 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


Pliki, z których będziemy korzystać
== Scenariusz zajęć ==
-----------------------------------
  Makefile
        Plik Makefile.


  err.h
=== Deskryptory, otwarte pliki
        Plik nagłówkowy biblioteki obsługującej błędy.
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.  


  err.c
; Rysunek
        Biblioteka obsługująca błędy.


  parent_pipe.c
Do otwierania pliku służy funkcja systemowa
        Tworzy proces, który ma wykonać program "child_pipe". Proces
:<tt>open</tt>.
        macierzysty komunikuje się z nim za pomocą łącza, do którego pisze
W wyniku przekazuje ona deskryptor otwartego pliku lub informacje o błędzie.  
        krótki komunikat.


  child_pipe.c
; Zadanie
        Czyta komunikat z deskryptora, którego numer jest
: Przeczytaj stronę ''man'' dotyczącą funkcji <tt>open</tt>
        przekazywany jako jedyny argument wywołania programu.
  parent_dup.c
        Wywołanie: parent_dup <command> [<arg_1> ... <arg_n>]
        Tworzy nowy proces, który ma wykonać polecenie z argumentami
        <arg_1> ... <arg_n>.  Proces macierzysty zapisuje do
        utworzonego łącza krótki komunikat. Proces potomny
        odbiera ten komunikat z łącza przekierowując standardowe
        wejście.


        Przykłady wywołań:
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).
                parent_dup cat
                parent_dup grep from
                parent_dup grep ludziska
                parent_dup wc
                parent_dup mail `whoami`


; 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:


Scenariusz zajęć
----------------


1. Deskryptory
  -----------
  Każdy proces utrzymuje tablicę deskryptorów. Tablica
  deskryptorów jest lokalna dla procesu i zawiera informacje o otwartych
  przez proces plikach. 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ł.
  Indeks w tej tablicy to właśnie deskryptor pliku.
  Do otwierania pliku służy funkcja systemowa open. W wyniku
  przekazuje ona deskryptor otwartego pliku lub informacje o błędzie.


  * Przeczytaj man open


  Zwróćmy uwagę, że jeśli proces dwukrotnie otworzy ten sam plik, to
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.  
  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).


  Do czytania z pliku służy funkcja systemowa read, a do zapisu funkcja
; Rysunek
  systemowa write. Zwróć uwagę, że 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.


  * Przeczytaj man read i man 2 write
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.


  Gdy proces wykonuje funkcje systemowa fork() tablica deskryptorów
; Test wyboru
  jest kopiowana do potomka. Zatem potomek "dziedziczy" po procesie
Przypuśćmy, że proces wykonuje następujący ciąg operacji:
  macierzystym wszystkie otwarte pliki. Co więcej deskryptory o tych
Załóżmy, że w pliku <tt>test.txt</tt> znajdują się po kolei znaki <tt>abcd</tt>.  
  samych numerach w procesie potomnym i macierzystym odnoszą się do
Zmienne tego procesu mają następujące wartości:
  tej samej pozycji w tablicy otwartych plików. Wniosek:
  ojciec i syn WSPÓŁDZIELĄ otwarte pliki: każda operacja wejścia/wyjścia
  w procesie ojca przesuwa wskaźnik pliku i powoduje, że kolejna
  operacja wejścia/wyjścia w procesie potomnym będzie dotyczyć
  KOLEJNEJ porcji danych.
  Funkcja systemowa exec() nie wpływa na postać tablicy deskryptorów.
  Proces po wykonaniu exec() zachowuje otwarte pliki (choć zapewne
  nie zna już ich numerów, bo zmienne, które przechowywały
  deskryptory otwartych plików przestały istnieć w chwili wykonania
  funkcji exec() ).


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:
---------
---------


  Napisz program tworzący dwa procesy: pierwszy z nich w pętli oczekuje na
  tekst podany z klawiatury, przesyła go za pomocą łącza do drugiego
  procesu, oczekuje na potwierdzenie od drugiego procesu (również
  za pomocą łącza). Proces powinien kończyć się po wczytaniu
  pustego tekstu.  Drugi proces cyklicznie oczekuje na komunikat,
  i potwierdza jego odbiór. Wykorzystaj w programie funkcje exec() oraz
  przekierowywanie standardowych deskryptorów (drugi proces powinien
  odczytywać deskryptor 0 i zapisywać na deskryptorze 1).


-->
-->

Wersja z 08:10, 13 cze 2006

Tematyka laboratorium

  1. Łącza nienazwane w systemie Unix: deskryptory plików, tworzenie i zamykanie łączy, duplikowanie łączy, zapis i odczyt z łącza
  2. Łącza nienazwane jako realizacja komunikacji asynchronicznej

Literatura uzupełniająca

  1. M. Rochkind, Programowanie w systemie Unix dla zaawansowanych, rozdz. 6.2 i 6.3
  2. W. R. Stevens, Programowanie zastowań sieciowych w systemie UNI, rozdz. 2.3 i 3.4
  3. M. J. Bach, Budowa systemu operacyjnego UNIX, rozdz. 7.1
  4. 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