INT 6. Metody komuni..
Transkrypt
INT 6. Metody komuni..
6. (INT) Metody komunikacji międzyprocesowej w systemach lokalnych i rozproszonych Komunikacja międzyprocesowa (Inter-Process Communication – IPC) – nazwa zbioru sposobów komunikacji pomiędzy wątkami jednego lub wielu procesów. Procesy mogą być uruchomione na jednym lub wielu komputerach połączonych w sieć. Techniki komunikacji międzyprocesowej dzielą się na: • Przenoszenie danych • Synchronizację Do zapewnienia komunikacji potrzebne są przynajmniej dwie funkcje interfejsowe – wysyłająca i odbierająca komunikat: send(id_odbiorcy, void* bufor, int ile) receive(id_nadawcy, void* bufor, int ile) Metody komunikacji międzyprocesowej Metoda komunikacji Systemy operacyjne Systemy Systemy lokalne rozproszone Pliki Większość systemów + + Sygnały Wszystkie systemy POSIX + - Gniazdka Większość systemów + + Kolejki komunikatów Wszystkie systemy POSIX, Windows + - Łącza nienazwane Wszystkie systemy POSIX, Windows + - Łącza nazwane Wszystkie systemy POSIX, Windows + - Semafory Wszystkie systemy POSIX, Windows + - Pamięć współdzielona Wszystkie systemy POSIX, Windows + - Zmapowany plik w pamięci Wszystkie systemy POSIX, Windows + + Przekazywanie komunikatów System z zaimplementowaną obsługą MPI, Java RMI, CORBA, RPC, ... + + UWAGA: Wszystkie funkcje opisywane poniżej odnoszą się do systemu UNIX. Pliki – plik może zostać otwarty w kilku procesach. Pojawia się tutaj problem spójności danych i wspólnego dostępu. Plik może być w jednej chwili odczytywany przez wiele procesów, ale zapisywać może tylko jeden proces w danej chwili. Po zapisie dane w innych procesach pozostają nieaktualne, jeśli zostały wczytane przed zapisanie pliku przez inny proces. Komunikacja może zachować w obrębie jednego systemu operacyjnego lub też pomiędzy kilkoma różnymi systemami, które współdzielą przestrzeń dyskową. Funkcje: • fopen() - otwarcie pliku • fwrite() - zapis do pliku • fread() - odczyt z pliku • fclose() - zamknięcie pliku Sygnały (POSIX) – asynchroniczne powiadomienia wysyłane do procesów będące reakcją na zaistniałe wydarzenia. Kiedy do procesu wysłany zostanie sygnał, przerwanie systemu operacyjnego przerywana normalny bieg. Wykonywanie może zostać przerwane podczas trwania jakiejkolwiek nieatomowej operacji. Jeśli proces posiadał wcześniej ustalone funkcje obsługi sygnałów, to zostaje wykonana właściwa funkcja. W przeciwnym wypadku wykonywana jest domyślna obsługa sygnałów. Każdy sygnał z wyjątkiem SIGKILL i SIGSTOP można przechwycić. Sygnały obsługiwane są tylko przy przejściu między trybem jądra systemu a trybem użytkownika. Funkcje: • signal() - rejestruje funkcję obsługi sygnału • sigset() - j/w • kill() - wysłanie sygnału Gniazdka – reprezentują dwukierunkowy punkt końcowy połączenia, co oznacza możliwość przyjmowania i wysyłania danych. W systemie UNIX gniazdko traktowane jest jak deskryptor otwartego pliku (można używać funkcji read(), write(), close()). Gniazdko tworzone jest za pomocą funkcji socket().Przed użyciem należy nadać mu adres funkcją bind(). Identyfikatorem konkretnego połączenia jest 5 atrybutów: adres odbiorcy, port odbiory, adres nadawcy, port nadawcy i rodzaj protokołu (TCP lub UDP). Dzięki niemu można jednoznacznie zidentyfikować połączenie. Funkcje: • socket() - utworzenie gniazdka • bind() - nadanie gniazdku adresu • connect() - przypisanie adresu drugiej strony • listen() - nasłuchiwanie na gniazdku • write(), send(), sendto() - zapis do gniazdka • read(), recv(), recvfrom() - odczyt z gniazdka • close() - zamknięcie gniazdka Kolejki komunikatów – są to listy jednokierunkowe zawierające komunikaty o określonym maksymalnym rozmiarze. Nowe komunikaty dodawane są na koniec listy, przez co zachowana jest kolejność ich wysyłania. Każdy komunikat ma parametr zwany typem, co pozwala na obsługę kilku „strumieni” komunikatów w ramach jednej kolejki. Funkcje: • msgget() - tworzenie kolejki komunikatów • msgsnd() - wysyłanie komunikatu • msgrcv() - odbieranie komunikatu • msgctl() - usuwanie (jeśli ustawimy w parametrze cmd flagę IPC_RMID) Łącza nienazwane – zwane też strumieniami pipe, pozwalają łączyć spokrewnione ze sobą procesy (rodzic - dziecko). Transmisja jest jednokierunkowa i z reguły łączy ona wyjście stdout jednego procesu z wejściem stdin drugiego. Łącza nienazwane tworzone są funkcją pipe(int fd[2]), która wypełnia dwuelementową tablicę deskryptorów. Deskryptor fd[0] jest końcem otwartym do czytania, a fd[1] do pisania. Oba końce traktowane są w UNIXie jak zwykłe deskryptory plików (można używać funkcji read(), write(), close()). Ponadto jądro systemu gwarantuje, że operacje zapisu nie przekraczające rozmiaru strumienia są niepodzielne. Strumień pipe jest buforem wielkości 4kB. Funkcje: • pipe() - tworzenie łącza nienazwanego • dup(), dup2() - tworzenie strumieni stdin-stdout (kopiowanie deskryptorów) • write() - zapis do łącza • read() - odczyt z łącza • close() - zamknięcie łącza Łącza nazwane – zwane też strumieniami FIFO, mogą być używane przez procesy nie spokrewnione ze sobą, a nawet przez procesy zupełnie różnych użytkowników. Posiadają one dowiązanie w systemie plików i są tworzone funkcją mknod() lub komendą mknod w UNIXie. Funkcja open() używana do otwarcia łącza do zapisu blokuje proces, aż do mementu otwarcia kolejki do odczytu i odwrotnie. Kolejki FIFO mają z reguły większy rozmiar bufora (4-16kB). Funkcje: • mknod() - tworzenie łącza nazwanego • open() - otwieranie łącza do pisania lub czytania • write() - zapis do łącza • read() - odczyt z łącza • unlink() - usuwanie łącza Łącza • • • • • nazwane i nienazwane mają wiele podobieństw: zamknięcie końca do pisania generuje u czytelników EOF zamknięcie końca do czytania generuje sygnał SIGPIPE wysyłany do wszystkich pisarzy zapis i odczyt przez standardowe funkcje read() i write() niepodzielność zapisów mniejszych niż rozmiar strumienia blokowanie procesów w przypadku przepełniania lub pustego bufora Semafory – abstrakcyjne typy danych, które stanowią klasyczną metodę kontroli dostępu do wspólnego zasobu. Na semafor składa się zmienna i kolejka procesów. Semafor może być binarny (zmienna przyjmuje tylko wartości 0 i 1) lub ogólny (zmienna nieujemna). Na semaforze można wykonywać 2 typy operacji: • zajmij(S) jeśli S > 0, to S-- i idź dalej, jeśi S = 0, to umieść proces w kolejce oczekujących na zwolnienie semafora i zaśnij • zwolnij(S) jeśli kolejka oczekujących jest pusta, to S++, jeśli ktoś czeka, to usuń go z kolejki oczekujących i obudź go, nie zmieniając wartości S Bieżąca wartość semafora odpowiada liczbie wolnych zasobów. Osiągnięcie wartości 0 oznacza, że kolejny proces żądający zasobu zostanie uśpiony. Możliwe jest zmniejszanie lub zwiększanie semafora o wartość inną niż 1, o ile nie doprowadzi to do osiągnięcia wartości ujemnej. Funkcje: • semget() - tworzenie semafora • semctl() - usuwanie semafora (jeśli ustawimy w parametrze cmd flagę IPC_RMID) • semop() - zwalnianie i zajmowanie semafora ◦ parametr sem_op < 0 – zajęcie semafora ◦ paramert sem_op > 0 – zwolnienie semafora ◦ parametr sem_op = 0 – synchronizacja z semaforem (czekanie aż osiągnie 0) Pamięć współdzielona – jest specjalnie utworzonym segmentem wirtualnej przestrzeni adresowej, do którego dostęp może mieć wiele procesów. W zależności od praw dostępu procesy mogą odczytywać i/lub zapisywać wartości w pamięci współdzielonej, przy czym w przypadku współbieżnie działających procesów konieczne jest najczęściej synchronizowanie dostępu np. za pomocą semaforów. Aby używać pamięci współdzielonej do komunikacji każdy proces musi najpierw wykonać funkcję shmget(), która utworzy lub znajdzie istniejący segment pamięci, a następnie znaleziony segment przypisać do swojej przestrzeni adresowej funkcją shmat(). Funkcje: • shmget() - utworzenie segmentu pamięci wspólnej lub znalezienie już istniejącego • shmctl() - usuwanie segmentu pamięci (parametr cmd musi mieć ustawioną flagę IPC_RMID) • shmat() - dołączenie segmentu pamięci do przestrzeni adresowej procesu • shmdt() - odłączenie segmentu pamięci od przestrzeni adresowej procesu Zmapowany plik w pamięci – możliwy jest dostęp do otwartych plików tak, jakby znajdowały się one w pamięci RAM, tzn. zamiast poruszać się po pliku za pomocą fseek() i pisać/czytać przez fwrite()/fread(), można używać wskaźników i zwykłych operacji przypisania. Pozwala na to funkcja mmap(): void *mmap(void *addr, size_t len, int prot, int flags, int filedes, off_t off); Funkcje: • mmap() - mapuje plik w pamięci RAM Przekazywanie komunikatów – na to zagadnienie składają się takie technologie jak RPC, MPI, Java RMI oraz wszystkie inne tego typu. Ogólna idea jest taka, że jeden z komputerów dostaje zlecenie zrealizowania określonego zadania. Od użytej technologii zależy, czy podzieli on to zadanie na kilka mniejszych i zleci ich realizację do innych komputerów, od których potem odbierze wyniki (MPI), czy też wywoła funkcję na innej maszynie o większej mocy, która szybciej wykona to zadanie (RPC). wszystkie obrazki pochodzą z pozycji [1] Literatura: przede wszystkim: [1] T. Surmacz, wykład z SSO http://infeka.wroclaw.pl/!archiwum/ssou1/Sieciowe %20systemy%20operacyjne%20UNIX/WYKLAD.PDF [PL] a, poza tym: [2] J. Ułasiewicz, wykłady z Programowania Współbieżnego i Rozproszonego, http://jedrzej.ulasiewicz.staff.iiar.pwr.wroc.pl/Progr-Wspol-i-Rozprosz/wyklad/SystRozprWstep13.pdf [PL] [3] J. Ułasiewicz, wykłady z Programowania Współbieżnego, http://jedrzej.ulasiewicz.staff.iiar.pwr.wroc.pl/ProgramowanieWspolbiezne/wyklad/Komuni kacjaWstep2.pdf [PL] [4] http://pl.wikipedia.org/wiki/Komunikacja_mi%C4%99dzyprocesowa [PL] [5] http://en.wikipedia.org/wiki/Inter-process_communication [EN] [6] http://en.wikipedia.org/wiki/Signal_(computing) [EN] [7] http://www.cs.put.poznan.pl/akobusinska/downloads/pamiec_wspoldzielona.pdf [PL]