1. Operacje na procesach

Dokument: pdf (185.6 KB)
  • 5 stron
Opublikowany 2017-07-23 02:06:13

29.03.2017, 01*05Systemy Operacyjne - Lekcja 6 - Segment 1 Strona 1 z 5http://oldwww.imio.pw.edu.pl/wwwvlsi/cad/teaching/soe/materialy/LEKCJA6/SEGMENT1/MAIN.HTM1. Operacje na procesach(1.1) Tworzenie procesu Pierwszy proces w systemie o identyfikatorze PID = 0 zostaje utworzony przez jądro podczas inicjalizacji systemu. Wszystkie pozostałe procesy powstają jako kopie swoich procesów macierzystych w wyniku wywołania jednej z funkcji systemowych: fork(), vfork(). pid_t fork(void); pid_t vfork(void); Jądro realizuje funcję fork() w następujący sposób: przydziela nowemu procesowi pozycję w tablicy procesów i tworzy nową strukturę procesu, przydziela nowemu procesowi identyfikator PID, tworzy logiczną kopię kontekstu procesu macierzystego: obszar instrukcji jest współdzielony, inne dane są kopiowane dopiero przy próbie modyfikacji przez proces potomny - polityka kopiowania przy zapisie (ang. copy-on-write), zwiększa otwartym plikom liczniki w tablicy plików i tablicy i-węzłów, kończy działanie funkcji w obydwu procesach zwracając następujące wartości: PID potomka w procesie macierzystym, 0 w procesie potomnym. Po zakończeniu funkcji fork() obydwa procesy, macierzysty i potomny, wykonują ten sam kod programu. Proces potomny rozpoczyna a proces macierzysty wznawia wykonywanie od instrukcji następującej bezpośrednio po wywołaniu funkcji fork(). Różnica w wartościach zwracanych przez fork() pozwala rozróżnić obydwa procesy w programie i przeznaczyć dla nich różne fragmenty kodu. Ilustruje to poniższy przykład. Różnica w działaniu funkcji vfork() polega na tym, że proces potomny współdzieli całą pamięć z procesem macierzystym. Ponadto proces macierzysty zostaje wstrzymany do momentu, gdy proces potomny wywoła funkcję systemową _exit() lub execve(), czyli zakończy się lub rozpocznie wykonywanie innego programu. Funkcja vfork() pozwala zatem zaoszczędzić zasoby systemowe w sytuacji, gdy nowy proces jest tworzony tylko po to, aby zaraz uruchomić w nim nowy program funkcją execve(). Przykład. Poniżej prezentowany jest kod programu implementującego typowy schemat tworzenia procesu potomnego z wykorzystaniem funkcji fork(). #include #include #include int main(void) { 29.03.2017, 01*05Systemy Operacyjne - Lekcja 6 - Segment 1 Strona 2 z 5http://oldwww.imio.pw.edu.pl/wwwvlsi/cad/teaching/soe/materialy/LEKCJA6/SEGMENT1/MAIN.HTM pid_t pid; if ((pid = fork()) == -1) { perror("fork"); exit(1); } if (pid == 0) { printf("Proces potomny: funkcja fork() zwrocila wartosc %d\n", pid); pid = getpid(); printf("Proces potomny: PID = %d\n", pid); exit(0); } else { printf("Proces macierzysty: funkcja fork() zwrocila wartosc %d\n", pid); pid = getpid(); printf("Proces macierzysty: PID = %d\n", pid); exit(0); } return(0); } (1.2) Kończenie procesu Proces może zakończyć swoje działanie w wyniku wywołania jednej z funkcji: void _exit(int status); void exit(int status); gdzie: status - status zakończenia procesu. Funkcja _exit() jest funkcją systemową, która powoduje natychmiastowe zakończenie procesu. Funkcja exit(), zdefiniowana w bibliotece, realizuje normalne zakończenie procesu, które obejmuje dodatkowo wywołanie wszystkich funkcji zarejestrowanych przez atexit() przed właściwym wywołaniem _exit(). int atexit(void (*function)(void)); Jeżeli nie zarejestrowano żadnych funkcji, to działanie exit() sprowadza się do _exit(). Funkcja exit() jest wołana domyślnie przy powrocie z funkcji main(), tzn. wtedy, gdy program się kończy bez jawnego wywołania funkcji. 29.03.2017, 01*05Systemy Operacyjne - Lekcja 6 - Segment 1 Strona 3 z 5http://oldwww.imio.pw.edu.pl/wwwvlsi/cad/teaching/soe/materialy/LEKCJA6/SEGMENT1/MAIN.HTM Realizacja funkcji przez jądro wygląda następująco: wyłączana jest obsługa sygnałów, jesli proces jest przywódcą grupy, jądro wysyła sygnał zawieszenia do wszystkich procesów z grupy oraz zmienia numer grupy na 0, zamykane są wszystkie otwarte pliki, następuje zwolnienie segmentów pamięci procesu, stan procesu zmieniany jest na zombie, status wyjścia oraz sumaryczny czas wykonywania procesu i jego potomków są zapisywane w strukturze task_struct, wszystkie procesy potomne przekazywane są do adopcji procesowi init, sygnał śmierci potomka SIGCHLD wysyłany jest do procesu macierzystego, następuje przełączenie kontekstu procesu. Pomimo zakończenia proces pozostaje w stanie zombie dopóki proces macierzysty nie odczyta jego statusu zakończenia jedną z funkcji wait(). (1.3) Oczekiwanie na zakończenie procesu potomnego Proces macierzysty nie traci kontaktu ze stworzonym procesem potomnym. Może wstrzymać swoje działanie w oczekiwaniu na jego zakończenie i odebrać zwrócony status. Pozwalają na to funkcje systemowe: pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int flags); gdzie: status - status zakończenia procesu potomnego, pid - identyfikator PID procesu potomnego, flags - flagi. Funkcja wait() wstrzymuje działanie procesu dopóki nie zakończy się dowolny z jego procesów potomnyc...

Komentarze do: 1. Operacje na procesach • 0