Zbigniew S. Szewczak Podstawy Systemów Operacyjnych
Transkrypt
Zbigniew S. Szewczak Podstawy Systemów Operacyjnych
Zbigniew S. Szewczak Podstawy Systemów Operacyjnych Wykład 6 Procesy. Toruń, 2004 Odrabianie wykładów ☛czwartek, 1.04.2004, S7, g. 12.00 za 19.05 ☛czwartek, 15.04.2004, S7, g. 12.00 za 12.05 Składowe systemu ☛Zarządzanie procesami (ang. process management) ☛Zarządzanie pamięcią operacyjną (ang. main memory management) ☛Zarządzanie plikami (ang. file management) ☛Zarządzanie systemem we/wy (ang. I/O system management) ☛Zarządzanie pamięcią pomocniczą (ang. secondary-storage management) Procesy ☛Koncepcja procesu ☛Planowanie procesów ☛Działania na procesach ☛Procesy współpracujące ☛Komunikacja międzyprocesowa ☛Wątki Koncepcja procesu ☛System operacyjny wykonuje wykonuje różne programy ☛system wsadowy - zadania ☛system z podziałem czasu - programy użytkownika (ang. user programs) lub prace (ang. tasks) ☛Będziemy utożsamiać zadanie i proces ! ☛Proces - program wykonywany sekwencyjnie ☛Koncepcja procesu zawiera ☛licznik rozkazów (ang. program counter) ☛stos (ang. stack) procesu - parametry, adresy powrotu ☛sekcję danych (ang. data section) - zmienne globalne Procesy a zasoby A B C pamięć wirtualna zasoby procesor we/wy we/wy pamięć Stan procesu ☛Wykonujący się proces zmienia swój stan (ang. state) ☛nowy (ang. new): proces został utworzony ☛aktywny (ang. running): są wykonywane instrukcje ☛oczekiwanie (ang. waiting): proces czeka na zdarzenie (np. zakończenie we/wy) ☛gotowy (ang. ready): proces czeka na przydział procesora ☛zakończony (ang. terminated): proces zakończył działanie Diagram stanów procesu nowy zakończony przerwanie przyjęcie wyjście gotowy obsłużenie zadrzenia lub operacja we/wy aktywny decyzja planisty czekający oczekiwanie na zdarzenie lub na wykonanie operacji we/wy Diagram stanów procesu - SVR5 utworzony (fork) wywłaszczony return brak pamięci fork swap in gotowy swap out gotowy wakeup uśpiony swap out swap out decyzja planisty aktywny (kernel) wakeup uśpiony w pamięci swap out return preempt exit aktywny (user) przerwanie, funkcja systemowa przerwanie, powrót z przerwania sleep zombie Blok kontrolny procesu (PCB) ☛Każdy proces w systemie operacyjnym jest reprezentowany przez blok kontrolny procesu (ang. process control block - PCB) zawierający ☛stan procesu - gotowy, nowy, aktywny, czekający, zatrzymany ☛licznik rozkazów - adres następnego rozkazu do wykonania w procesie ☛rejestry procesora - zależą od architektury komputera: akumulatory, rejestry (ogólne, bazowe, indeksowe) wskaźniki stosu przechowywane aby proces mógł być kontynuowany po przerwaniu Blok kontrolny procesu (PCB) ☛(c.d.) ☛informacje o planowaniu przydziału procesora - priorytet procesu, wskaźniki do kolejek porządkujących zamówienia ☛informacje o zarządzaniu pamiecią - zawartości rejestrów granicznych, tablice stron, tablice segmentów w zależności od systemu używanej pamięci ☛informacje do rozliczeń - ilość zużytego czasu procesora i czasu rzeczywistego, ograniczenia czasowe, numery kont, numery zadań ☛informacje o stanie we/wy - lista zaalokowanych urządzeń, wykaz otwartych plików Blok kontrolny procesu (c.d.) wskaźnik stan procesu numer procesu licznik rozkazów rejestry ograniczenia pamięci wykaz otwartych plików . . . Przełączanie procesora proces A system operacyjny proces B przerwanie lub wywołanie systemowe wykonywanie przechowaj stan w bloku kontrolnym 0 . . . bezczynność odtwórz stan z bloku kontrolnego 1 bezczynność przerwanie lub wywołanie systemowe . . . przechowaj stan w bloku kontrolnym 1 bezczynność odtwórz stan z bloku kontrolnego 0 wykonywanie wykonywanie Struktura tablic kontrolnych tablice pamięci obraz procesu pamięć tablice we/wy proces 1 urządzenia pliki tablice plików procesy tablica procesu obraz procesu proces 1 proces 2 . . . proces n proces n Przykład - IBM/360 & OS/MVT TCB TCB save task A save TCB link ep=B link ep=A task B save return attach ep=C, ECB=E TCB task C return wait 1,E Supervisor post E return ECB Kolejki planowania procesu ☛Wchodzące do systemu procesy tworzą kolejkę zadań (ang. job queue) ☛Gotowe do działania procesy oczekujące w pamięci głównej na wykonanie tworzą kolejkę procesów gotowych (ang. ready queue) ☛Procesy czekające na konkretne urządzenie tworzą kolejkę do urządzenia (ang. device queue) ☛Procesy migrują między kolejkami Kolejka zadań i kolejki do urządzeń we/wy blok kontrolny 7 kolejka procesów gotowych jednostka taśmowa czoło ogon rejestry . . . czoło ogon blok kontrolny 3 jednostka dyskowa 0 czoło ogon jednostka dyskowa 1 czoło ogon jednostka terminali czoło ogon blok kontrolny 2 blok kontrolny 14 blok kontrolny 2 rejestry . . . blok kontrolny 6 Diagram kolejek ☛Diagram kolejek służy do opisu planowania procesów ☛prostokąt określa kolejkę; kółko to zasoby; strzałka to przepływ ☛nowy proces jest w kolejce procesów gotowych ☛zostaje wybrany (ang. dispatched) i otrzymuje procesor ☛proces może zamówić we/wy i trafia do kolejki oczekujących na we/wy ☛proces może utworzyć potomka i czekać na jego zakończenie ☛proces może zostać wywłaszczony wskutek przerwania i przeniesiony do kolejki procesów gotowych Diagram kolejek w planowaniu procesów kolejka procesów gotowych we/wy CPU kolejka operacji we/wy zamówienia operacji we/wy zużycie kwantu czasu potomek działa wystąpienie przerwania powołanie procesu potomnego czekanie na przerwanie Planiści ☛Planista długoterminowy (ang. long-term scheduler) lub planista zadań (ang. job scheduler) - wybiera procesy, które powinny być sprowadzone do pamięci z kolejki procesów gotowych ☛Planista krótkoterminowy (ang. short-term scheduler) lub planista przydziału procesora (ang. CPU scheduler) - wybiera proces następny do wykonania z kolejki procesów gotowych i przydziela mu procesor Planiści (c.d.) ☛Planista krótkoterminowy jest wołany bardzo często (milisekundy) dlatego musi być bardzo szybki ☛Planista długoterminowy jest wołany rzadko (sekundy, minuty) dlatego może nie być szybki ☛Planista długoterminowy nadzoruje stopień wieloprogramowości (liczbę procesów w pamięci) Planiści (c.d.) ☛Proces może być opisany jako jeden z ☛ograniczony przez we/wy (ang. I/O bound) - więcej czasu zajmuje we/wy niż dostęp do procesora ☛ograniczony przez dostęp do procesora (ang. CPU bound) więcej czasu zajmują obliczenia, we/wy sporadyczne ☛Planista długoterminowy powinien dobrać mieszankę procesów (ang. process mix) zawierającą zarówno procesy ograniczone przez we/wy jak i procesor ☛Planista średnioterminowy(ang. medium-term scheduler) - swapping (wymiana) w celu uzyskania lepszego doboru procesów Planista średnioterminowy sprowadź do pamięci (swap in) usunięte procesy częściowo wykonane kolejka procesów gotowych we/wy usuń z pamięci (swap out) CPU kolejki procesów oczekujących na we/wy koniec Przełączanie kontekstu ☛Gdy procesor przełącza do innego procesu system musi zachować stan starego procesu i załadować zachowany stan nowego procesu. Czynność tę nazywamy przełączaniem kontekstu (ang. context switch) ☛Przełączanie kontekstu jest ceną za wieloprogramowość; system operacyjny nie wykonuje wtedy żadnej użytecznej pracy ☛Czas przełączenia kontekstu zależy od sprzętu (zwykle od 1 do 1000 milisekund) Działania na procesach tworzenie procesu ☛Proces macierzysty (ang. parent process) tworzy nowy proces - potomka (ang. child process) i każdy nowy proces może tworzyć nowe procesy, które tworzą drzewo procesów ☛Dzielenie zasobów ☛proces macierzysty i potomek dzielą wszystkie zasoby ☛proces macierzysty i potomek dzielą część zasobów ☛proces macierzysty i potomek nie dzielą żadnych zasobów Drzewo procesów w UNIXie proces root proces pagedaemon proces swapper proces użytkownika 1 proces init proces użytkownika 2 proces użytkownika 3 Tworzenie procesu (c.d.) ☛Wykonanie ☛proces macierzysty i potomek działają współbieżnie ☛proces macierzysty czeka aż potomek zakończy ☛Przestrzeń adresowa nowego procesu ☛potomek jest kopią procesu macierzystego ☛potomek ładuje do przestrzeni adresowej nowy program Przykłady ☛UNIX ☛funkcja systemowa fork tworzy nowy proces zawierający kopię przestrzeni adresowej procesu pierwotnego ☛funkcja systemowa execlp użyta po fork powoduje zastąpienie zawartości pamięci przez nowy program (ładuje plik binarny do pamięci niszcząc obraz pamięci zawierający wywołanie execlp) ☛proces macierzysty czeka aż potomek skończy (funkcja systemowa wait) w kolejce procesów gotowych ☛Przykład pod Cygwinem Przykład - Unix #include <stdio.h> int main(void) { int pid; /* fork another process */ pid = fork(); if (pid < 0) { /* error occurred */ fprintf(stderr, "Fork Failed\n"); exit(-1); } else if (pid == 0) { /* child process */ execlp("/bin/ls","ls",NULL); } else { /* parent process */ /* parent will wait for the child to complete */ wait(NULL); printf("Child Complete\n"); exit(0); } } Przykład ☛new.c int main() { } execlp("/bin/ps","ps",0); ☛gcc -o new new.c ☛./new ☛ps Przykład - prosty shell #define TRUE 1 while (TRUE) { /* pętla */ type_prompt( ); /* prompt */ read_command (command, parameters) /*czytaj komendę */ if (fork() != 0) { /* Kod rodzica */ waitpid( -1, &status, 0); } else { /* Kod potomka */ execve (command, parameters, 0); } } /* proces potomny */ /* czekaj */ /* wykonaj komendę */ Przykłady (c.d.) ☛DEC VMS ☛tworzy proces i ładuje do niego program ☛Windows NT - oba modele ☛duplikowanie przestrzeni adresowej procesu macierzystego ☛proces macierzysty może określić nazwę programu do załadowania do przestrzeni adresowej nowego procesu Kończenie procesu ☛Proces kończy się (ang. terminate) wówczas, gdy wykona swoją ostatnią instrukcję i za pomocą funkcji systemowej exit poprosi system operacyjny aby go usunął a także aby ☛przekazał dane wyjściowe z potomka do procesu macierzystego (za pośrednictwem funkcji systemowej wait wydanej w procesie macierzystym) ☛wszystkie zaalokowane zasoby (pamięć fizyczna i wirtualna, otwarte pliki, bufory we/wy) odebrał potomkowi Kończenie procesu (c.d.) ☛Proces macierzysty wywołuje funkcję systemową abort bowiem ☛potomek nadużył zasobów ☛wykonywanie potomka stało się jałowe ☛proces macierzysty kończy się ☛system operacyjny nie pozwala potomkowi na działanie jeśli proces macierzysty kończy działanie ☛system operacyjny wymusza zakończenie wszystkich potomków - kończenie kaskadowe (ang. cascading termination) Zombie ☛zombie.c #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main () { pid_t child_pid; /* Create a child process. */ child_pid = fork (); if (child_pid > 0) { /* This is the parent process. Sleep for a minute. */ sleep (60); } else { /* This is the child process. Exit immediately. */ exit (0); } } ☛ps -al Procesy współpracujące ☛Procesy współbieżne mogą być niezależne (ang. independent) lub współpracujące (ang. cooperating) ☛Procesy współpracujące mogą oddziaływać na inne procesy w systemie lub inne procesy w systemie mogą oddziaływać na nie ☛Korzyści ze współpracy procesów ☛dzielenie informacji ☛przyspieszanie (obliczeń) ☛modularność - możliwość konstruowania systemów ☛wygoda - użytkownik może mieć wiele procesów Problem producent-konsument ☛Paradygmat procesów współpracujących: proces-producent wytwarza do bufora informację, którą proces-konsument zużywa (z bufora) ☛nieograniczony bufor (ang. unbounded-buffer) - producent wytwarza nieustannie jednostki do nieograniczonego bufora ☛ograniczony bufor (ang. bounded-buffer) - producent wytwarza jednostki do bufora ograniczonego rozmiaru (n), który konsument opróżnia ☛Dostęp do bufora np. przy pomocy pamięci dzielonej (IPC) Rozwiązanie problemu bufor ograniczony Proces konsumenta i producenta korzystają z wspólnych zmiennych #define BUFFER_SIZE 10 typedef struct { ... } item; item buffer[BUFFER_SIZE]; int in = 0; int out = 0; # # # # in - następne wolne miejsce w buffer out - pierwsze zajęte miejsce w buffer in=out - buffer jest pusty in+1 mod n = out - buffer jest pełny Proces producenta item nextProduced; while (1) { /* produce an item in nextProduced */ while (((in + 1) % BUFFER_SIZE) == out) ; /* do nothing */ buffer[in] = nextProduced; in = (in + 1) % BUFFER_SIZE; } Proces konsumenta item nextConsumed; while (1) { while (in == out) ; /* do nothing */ } nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; /* consume the item in nextConsumed */ Komunikacja międzyprocesowa ☛Komunikacja międzyprocesowa (ang. interprocess-communication - IPC) udogodnienia systemu pozwalające współpracującym procesom na kontaktowanie się ze sobą ☛System przekazywania komunikatów (ang. message system) - sposób realizacji komunikacji międzyprocesorowej pozwalający nie odwoływać się do zmiennych dzielonych Komunikacja międzyprocesowa ☛Komunikacja międzyprocesowa dostarcza dwóch operacji ☛nadaj (komunikat) (ang. send (message)) ☛odbierz(komunikat) (ang. receive(message)) ☛Jeśli procesy P i Q chcą się skomunikować to ☛muszą ustanowić łącze komunikacyjne ☛nadawać i odbierać komunikaty ☛Implementacja ☛fizyczna (np. pamięć dzielona, szyna sprzętowa) ☛logiczna (np. własności logiczne) Problemy związane z implementacją ☛Jak ustanawiać połączenia ☛Czy łącze może być powiązane z więcej niż dwoma procesami? ☛Ile może być łączy na każdą parę procesów ☛Jaka jest pojemność łącza? Czy łącze ma obszar buforowy? Jak duży? ☛Jaki jest rozmiar komunikatów (stały, zmienny)? ☛Czy łącze jest jest jedno- czy dwukierunkowe ☛Komunikacja (bez)pośrednia, (a)symetryczna? Komunikacja bezpośrednia ☛Proces musi jawnie nazwać odbiorcę ☛nadaj(P,komunikat) - nadaj komunikat do procesu P ☛odbierz(Q,komunikat) - odbierz komunikat od procesu Q ☛Własności łącza ☛łącze jest ustanawiane automatycznie, do komunikowania wystarczy znajomość identyfikatorów ☛łącze dotyczy dokładnie dwóch procesów ☛między każdą parą procesów istnieje dokładnie jedno łącze ☛łącze jest zwykle dwukierunkowe, ale może być jednokierunkowe Komunikacja pośrednia ☛Komunikaty są nadawane i odbierane za pomocą skrzynek pocztowych (ang. mailboxes) nazywanych także portami (ang. ports) ☛każda skrzynka ma swój unikalny identyfikator ☛procesy komunikują się jeśli mają wspólną skrzynkę ☛Własności łącza ☛łącze jest ustanawiane jedynie wtedy gdy procesy dzielą skrzynkę ☛łącze może być związane z więcej niż dwoma procesami ☛każda para procesów może mieć kilka łączy z których każdy odpowiada jakiejś skrzynce ☛łącze może być jedno- lub dwukierunkowe Komunikacja pośrednia (c.d) ☛System operacyjny dostarcza mechanizmów do ☛tworzenia nowej skrzynki ☛nadawania i odbierania komunikatów za pomocą skrzynki ☛likwidowania skrzynki ☛Dzielenie skrzynki : P, Q, R dzielą skrzynkę A ☛P nadaje; Q i R odbierają ☛który proces otrzyma komunikat nadany przez P? ☛Rozwiązanie ☛zezwalać jedynie na łącza między dwoma procesami ☛pozwalać najwyżej jednemu procesowi na odbiór ☛pozwalać aby system wybrał i poinformował odbiorcę Buforowanie ☛Łącze ma pojemność określającą maksymalną liczbę komunikatów, które mogą w nim przebywać dlatego musimy mieć kolejkę komunikatów ☛Metody implementacji kolejki ☛pojemność zerowa - nadawca musi czekać aż odbiorca odbierze komunikat ☛pojemność ograniczona - nadawca musi poczekać jeśli kolejka jest pełna ☛pojemność nieograniczona - nadawca nigdy nie czeka Sytuacje wyjątkowe ☛Zakończenie procesu ☛system musi powiadamiać o zakończeniu procesu ☛Utrata komunikatów ☛system powinien wykryć utratę komunikatu ☛proces nadawczy powinien umieć powtórzyć komunikat ☛system zawiadamia proces nadawczy ☛Zniekształcenie komunikatów ☛sumy kontrolne, sprawdzanie parzystości, CRC System Mach ☛System oparty na komunikatach nadawanych i odbieranych przez skrzynki pocztowe zwane portami ☛Każde zadanie ma dwie specjalne skrzynki ☛skrzynka jądra (ang. kernel mailbox) do komunikowania się z zadaniem ☛skrzynka zawiadomień (ang. notify mailbox) do wysyłania zawiadomień o zdarzeniach ☛Funkcje systemowe ☛msg_send, msg_receive, msg_rpc (wysyła i czeka na odpowiedź), port_allocate (tworzy skrzynkę) ☛przykład wykorzystania mechanizmu RPC do komunikowania między systemami via msg_rpc System Mach (c.d.) ☛Jeśli skrzynka jest pełna to wątek nadawczy ☛czeka aż się zwolni miejsce w skrzynce ☛czeka co najwyżej n mililsekund ☛nie czeka ☛czasowo przechowuje komunikat ☛Słaba wydolność systemu powodowana kopiowaniem komunikatu od nadawcy do skrzynki a potem ze skrzynki do odbiorcy ☛rozwiązanie: odwzorowanie przestrzeni adresowej nadawanego komunikatu na przestrzeń odbiorcy, można tak zrobić jedynie dla komunikatów systemowych Windows 2000 ☛Modularny system operacyjny, w którym programy użytkowe kontaktują się za pomocą mechanizmu przekazywania komunikatów ☛Udogodnienie wywoływania procedur lokalnych (ang. local procedure call facility - LPC) służy do komunikacji między procesami na tej samej maszynie ☛przypomina mechanizm RPC, ale jest zoptymalizowane ☛wykorzystuje obiekt portu łączącego i komunikacyjnego Windows 2000 (c.d.) ☛Komunikacja ☛klient zaopatruje się w uchwyt do obiektu portu łączącego podsystemu ☛klient wysyła prośbę o połączenie ☛serwer tworzy dwa prywatne porty komunikacyjne i przekazuje klientowi uchwyt do jednego z nich ☛klient i serwer korzystają z odpowiednich uchwytów portowych w celu wysyłania komunikatów lub przywołań oraz nasłuchiwania odpowiedzi ☛Trzy typy komunikacji zależnie od wielkości komunikatu Komunikacja klient/serwer implementacje ☛Gniazda (ang. sockets) ☛przykład w Javie: time-of-day serwer ☛RPC (ang. Remote Procedure Calls) ☛RMI (ang. Remote Method Invocation) ☛przykład w Javie: time-of-day serwer Klient - gniazda import java.net.*; import java.io.*; public class DateClient { public static void main(String[] args) throws IOException { InputStream in = null; BufferedReader bin = null; Socket sock = null; try { sock = new Socket("127.0.0.1",6013); in = sock.getInputStream(); bin = new BufferedReader(new InputStreamReader(in)); String line; while( (line = bin.readLine()) != null) System.out.println(line); } catch (IOException ioe) { System.err.println(ioe); } finally { sock.close(); } } } import java.net.*; import java.io.*; public class DateServer { public static void main(String[] args) throws IOException { Socket client = null; ServerSocket sock = null; try { sock = new ServerSocket(6013); // now listen for connections while (true) { client = sock.accept(); System.out.println("server = " + sock); System.out.println("client = " + client); // we have a connection PrintWriter pout = new PrintWriter(client.getOutputStream(),true); // write the Date to the socket pout.println(new java.util.Date().toString()); pout.close(); client.close(); } } catch (IOException ioe) { System.err.println(ioe); } finally { if (sock != null) sock.close(); if (client != null) client.close(); } } } RPC ☛Wywołania procedur między systemami ☛Namiastka (ang. stub, proxy) po stronie klienta do przekazania parametrów zdalnej procedurze oraz po stronie serwera do wywołania procedury ☛Klient: namiastka procedury zdalnej lokalizuje port na serwerze i przetacza (ang. marshall) opakowane parametry i komunikaty ☛Serwer: namiastka procedury na serwerze rozpakowuje parametry, wywołuje procedurę i zwraca wynik w ten sam sposób Architektura RPC aplikacja klienta odpowiedź lokalna zdalna aplikacja serwera odpowiedź lokalna odpowiedź lokalna lokalne wywołanie procedury lokalne wywołanie procedury namiastka aplikacja lokalna lub system operacyjny namiastka przetaczanie mechanizm RPC RPC mechanizm RPC RPC - implementacja Sun użytkownik zleca jądru wysłanie komunikatu RPC do procedury X jądro wysyła komunikat do demona randezvous z pytaniem o numer portu from: klient; to: serwer port: randezvous re: adres dla RPC X randezvous otrzymuje komunikat i przygotowuje odpowiedź jądro wstawia port P do komunikatu RPC użytkownika from: serwer; to: klient port: kernel; re: adres adres dla RPC X <P> randezvous odpowiada klientowi: port P from: klient; to: serwer port: P ; <treść> demon nasłuchujący na porcie P otrzymuje komunikat jądro wysyła komunikat RPC użytkownika jądro otrzymuje odpowiedź i przekazuje ją do użytkownika klient from: RPC; port: P to: klient; port: jądro <wyniki> komunikaty demon obsługuje żądanie i przygotowuje wyniki serwer RMI ☛Realizacja RPC na maszynie Javy ☛Pozwala jednej maszynie wywołać metodę na zdalnym obiekcie ☛Klient: namiastka (ang. stub) tworzy paczkę (ang. parcel) zawierającą nazwę metody wywoływanej na serwerze oraz parametry i przetacza je do serwera ☛Serwer: szkielet (ang. skeleton) odpowiada za rozpakowanie parametrów i wywołanie metody RMI - przetaczanie klient zdalny obiekt val=serwer.metoda(A,B) boolean metoda(Obiekt x, Obiekt y) { implementacja metody metoda ........... } namiastka szkielet A, B metoda zmienna boolowska Serwer - implementacja import java.rmi.*; import java.rmi.server.UnicastRemoteObject; import java.util.Date; public class RemoteDateImpl extends UnicastRemoteObject implements RemoteDate { public RemoteDateImpl() throws RemoteException { } public Date getDate() throws RemoteException { return new Date(); } public static void main(String[] args) { try { /* we only need to install this to distribute classes * System.setSecurityManager(new RMISecurityManager());*/ RemoteDate dateServer = new RemoteDateImpl(); // Bind this object instance to the name "DateServer" Naming.rebind("DateServer", dateServer); //Naming.rebind("//localhost:1099/DateServer", dateServer); System.out.println("DateServer bound in registry"); } catch (Exception e) { System.err.println(e); } } } Serwer - kompilacja, rejestracja ☛RemoteDate.java import java.util.Date; import java.rmi.*; public interface RemoteDate extends Remote { public abstract Date getDate() throws RemoteException; } ☛javac RemoteDate*.java ☛rmic RemoteDateImpl ☛rmiregistry & Klient - kompilacja ☛RMIClient.java import java.rmi.*; public class RMIClient { public static void main(String args[]) { try { /* We only need this for loading remote classes * System.setSecurityManager(new RMISecurityManager());*/ String host = "rmi://127.0.0.1/DateServer"; RemoteDate dateServer = (RemoteDate)Naming.lookup(host); System.out.println(dateServer.getDate()); } catch (Exception e) { System.err.println(e); } } } ☛cp ../server/RemoteDateImpl_Stub.class . ☛cp ../server/RemoteDate.class . ☛javac RMIClient.java RMI - uruchomienie (Cygwin) ☛W oknie serwera ☛java RemoteDateImpl ☛DataServer bound in registry ☛netstat ☛W oknie klienta ☛netstat ☛port 1099 ☛java RMIClient ☛Thu Mar 18 09:55:29 CET 2004 ☛Ctrl-C w oknie serwera Wątki ☛Wątek (ang. thread) nazywany niekiedy procesem lekkim (ang. lightweight process LWP) jest podstawową jednostką wykorzystania procesora. W skład tej jednostki wchodzą ☛licznik rozkazów ☛zbiór rejestrów ☛obszar stosu Wątki (c.d.) ☛Wątek współużytkuje z innymi równorzędnymi wątkami ☛sekcję kodu ☛sekcję danych ☛zasoby systemu (takie jak otwarte pliki i sygnały) zwane wspólnie zadaniem (ang. task) ☛Proces tradycyjny lub ciężki (ang. heavyweight) to zadanie o jednym wątku Wątki - przykład #include <pthread.h> #include <stdio.h> int sum; /* this data is shared by the thread(s) */ void *runner(void *param); /* the thread */ main(int argc, char *argv[]) { pthread_t tid; /* the thread identifier */ pthread_attr_t attr; /* set of attributes for the thread */ if (argc != 2) { fprintf(stderr,"usage: a.out <integer value>\n"); exit(); } if (atoi(argv[1]) < 0) { fprintf(stderr,"Argument %d must be non-negative\n",atoi(argv[1])); exit(); } /* get the default attributes */ pthread_attr_init(&attr); Wątki - przykład (c.d.) /* create the thread */ pthread_create(&tid,&attr,runner,argv[1]); /* now wait for the thread to exit */ pthread_join(tid,NULL); printf("sum = %d\n",sum); } /** * The thread will begin control in this function */ void *runner(void *param) { int upper = atoi(param); int i; sum = 0; if (upper > 0) { for (i = 1; i <= upper; i++) sum += i; } pthread_exit(0); } Procesy wielowątkowe kod rejestry dane pliki stos kod dane pliki rejestry rejestry rejestry stos stos stos Wątki - korzyści ☛W zadaniu wielowątkowym (ang. multithreaded task) w czasie gdy wątek serwer jest zablokowany i oczekuje, drugi wątek tego samego zadania może się wykonywać ☛współpraca wielu wątków w tym samym zadaniu zwiększa przepustowość oraz polepsza wydajność systemu ☛program użytkowy wykorzystujący wspólny bufor (np. producent-konsument) stosuje wątki Przykład RPC - jeden wątek czas żądanie RPC żądanie RPC proces serwer 1 serwer 2 zablokowany, oczekuje na odpowiedź od RPC zablokowany, oczekuje na procesor używany przez wątek B wykonywany Przykład RPC - dwa wątki czas żądanie RPC serwer 1 wątek A proces wątek B żądanie RPC serwer 2 zablokowany, oczekuje na odpowiedź od RPC zablokowany, oczekuje na procesor używany przez wątek B wykonywany Wątki a proces ☛Zablokowanie procesu powoduje zablokowanie wszystkich jego wątków albowiem dzielą one tę samą przestrzeń adresową ☛Zakończenie procesu wiąże się z zakończeniem wszystkich jego wątków ☛ Wątki - działanie ☛Wątki mogą tworzyć wątki potomne (ang. spawn) i blokować (ang. block) się do czasu zakończenia wywołań systemowych ☛Działanie wątków przypomina działanie procesów (gotowe, zablokowane, aktywne (ang. unblock), kończące (ang. finish)) jednak wątki nie są niezależne od siebie ☛np. oczekiwanie na we/wy ☛przechowanie kontekstu: rejestry, licznik i stos ☛wybranie nowego wątku z kolejki wątków gotowych ☛ Typy wątków ☛Wątki (ang. kernel-level) obsługiwane przez jądro ☛Mach, OS/2, Windows 9x/NT/2K, Linux, BeOS ☛Wątki tworzone na poziomie użytkownika (ang. user-level) za pomocą funkcji bibliotecznych ☛system Andrew ☛POSIX: Pthreads, Mach: C-threads, Solaris 2: UI-threads ☛zaleta: szybsze przełączanie, wada: planowanie wątków ☛Hybrydowe podejście - Solaris 2 ☛Wątki zarządzane przez JVM ☛ Relacje międzywątkowe przestrzeń użytkownika biblioteka wątków P biblioteka wątków P P przestrzeń jądra wątki poziomu użytkownika wątek poziomu użytkownika wątki poziomu jądra wątek poziomu jądra P wątki mieszane P proces Sposoby odwzorowań wątków ☛Wiele do jednego (ang. Many-to-One) ☛Jeden do jednego (ang. One-to-One) ☛OS/2, Windows 9x/NT/2K ☛Wiele do wielu (ang. Many-to-Many) ☛Solaris 2, IRIX, HP-UX, Windows NT/2K (ThreadFiber) ☛ Many-to-One wątek użytkownika wątek jądra One-to-one wątek użytkownika wątek jądra Many-to-many wątek użytkownika wątek jądra Solaris 2 - wątki ☛Solaris 2 jest klonem UNIXa realizującym zarówno wątki na poziomie jądra jak i użytkownika, symetryczne wieloprzetwarzanie i planowanie w czasie rzeczywistym ☛Solaris 2 definiuje pośredni poziom wątków: między wątkami użytkownika i jądra występują procesy lekkie w skrócie LWP którymi zawiaduje biblioteka wątków ☛Każde zadanie ma przynajmniej jeden proces lekki (LWP) do którego są podłączone wątki poziomu użytkownika Solaris 2 - wątki (c.d.) ☛Zasoby potrzebne wątkom ☛wątek jądrowy (podlega planowaniu i może być przypięty (ang. pinned) do procesora) ☛mała struktura danych i stos ☛przełączanie wątków nie wymaga informacji o pamięci ☛przełączanie stosunkowo szybkie ☛proces lekki (LWP) ☛blok kontrolny procesu z danymi rejestrowymi ☛informacje rozliczeniowe ☛informacje dotyczące pamięci ☛przełączanie kontekstu dość wolne ☛wątek użytkownika ☛stos i licznik rozkazów ☛szybkie gdyż jądro nie jest angażowane w ich planowanie Solaris 2 - wątki (c.d.) wątek użytkownika proces lekki wątek jądrowy procesor Java - wątki ☛Język Java dostarcza mechanizmów do tworzenia i zarządznie wątkami ☛Rozszerzenie klasy Thread ☛http://people.westminstercollege.edu/faculty/ggagne/osc/index. html ☛Zarządzanie wątkami przez JVM ☛Odwzorowanie wątków: jądro - JVM ☛W9x/NT/2K - one-to-one ☛Solaris 2 - many-to-one (green threads) ☛ Podsumowanie (1) ☛Proces to wykonywany program, który może znajdować się w jednym z następujących stanów: nowy, gotowy, aktywny, oczekiwania lub zakończony ☛Proces, który nie jest wykonywany jest umieszczany w kolejce oczekujących na coś ☛kolejka zamówień we/wy ☛kolejka procesów gotowych (oczekujących na procesor) ☛Proces jest reprezentowany przez blok kontrolny procesu, który to blok jest elementem listy bloków kontrolnych procesów gotowych Podsumowanie (2) ☛Planowanie ☛długoterminowe - dopuszczanie procesów do rywalizacji o procesor ☛krótkoterminowe - wybieranie procesów gotowych ☛Procesy mogą działać współbieżnie i być niezależne lub współpracować ☛Procesy współpracujące komunikują się ☛za pomocą pamięci dzielonej ☛za pomocą systemu komunikatów Podsumowanie (3) ☛Procesy współpracujące, które dzielą logiczną przestrzeń adresową można implementować w postaci procesów lekkich, czyli wątków ☛Wątek jest podstawową jednostką wykorzystania procesora, która dzieli z innymi równorzędnymi wątkami swoją sekcję kodu i danych oraz zasoby systemu operacyjnego łącznie nazywa się to zadaniem ☛Wykorzystanie wątków pozwala na uniknięcie kosztownego przełączania kontekstu w procesach ciężkich