procesy odrębne Unikatowy PID (2-32000) Zmienne Zbiory deskryptorów plików Przestrzeń stosu (lokalne zmienne, wywołania funkcji) Środowisko Licznik rozkazów dzielone Kod programu brak możliwości zapisu Biblioteki systemowe
Uruchamianie procesów #include <stdlib.h> system(const char *string) zwraca: 127 nie można uruchomić powłoki -1 inny błąd kod wy polecenia równoważne - sh c string oczekuje na zakończenie procesu chyba że: system( polecenie & );
#include <unistd.h> char **environ; Zastepowanie procesu (rodzina funkcji exec) int execl(const char *path, const char *arg0, (char *) 0); int execlp(const char *path, const char *arg0, (char *) 0); int execle(const char *path, const char *arg0, (char *) 0,const char *envp[]); int execv(const char *path, const char *argv[]); int execvp(const char *path, const char *argv[]); int execve(const char *path, const char *argv[], const char *envp[]);
.. #include. int main() { printf( start\n ); execlp( ps, ps, aux,0); printf( koniec\n ); exit(0); } PID ps a PID proc. mac. brak powrotu do pr. mac. proces potomny dziedziczy deskryptory plików
Duplikowanie procesu #include <sys/types.h> #include <unistd.h> pid_t fork(void); Zwraca: pid procesu potomnego - w procesie macierzystym 0 - w procesie potomnym -1 - błąd Proces potomny dziedziczy: zmienne, deskryptory plików
#include <sys/types.h> #include <unistd.h> #include<stdio.h>.. switch (fork()) { case 1; printf( fork error ); exit(1); case 0; /* akcja dla procesu potomnego */ break; default; /* akcja dla procesu macierzystego */ break; }
#include<sys/types.h> #include<unistd.h>. switch (fork()) { case 1; printf( fork error ); exit(1); case 0; /* proces potomny */ execl(./program, program,null); exit(2); default; /* proces macierzysty */ }
getpid() zwraca pid procesu wywołującego zombie proces potomny po zakończeniu pozostaje w systemie (aż pr. mac. wykona wait lub się zakończy) sierota proces mac. zakończył pracę nieprawidłowo (PPID=1)
oczekiwanie na zakończenie potomka #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *stat); pid_t waitpid(pid_t pid, int *stat, int opt); wait - zwraca pid procesu, który się zakończył pod adresem wskazywanym przez status umieszczany jest status zakończenia waitpid opt =np. WNOHANG zapobiega wstrzymywaniu procesu wywołującego (zwraca 0)
#include<stdio.h> int main() {int i,id,status; Zarządzanie procesami: fprintf(stdout, Mój PID %d\n,getpid()); fprintf(stdout, Teraz tworze potomka\n ); id=fork(); if (id==0) fprintf(stdout, id=%d to pisze proces potomny PID= %d\n,id,getpid()); else { wait(&status); fprintf(stdout, id =%d to pisze proces macierzysty id= %d\n,id,getpid()); }; fprintf(stdout, A to pisza obydwa procesy PID=%d\n,getpid());}
sygnały pliki Komunikacja między procesami: łącza komunikacyjne łącza nazwane ( kolejki FIFO) semafory komunikaty pamięć dzielona
Sygnały - jądro systemu oraz procesy mogą wysyłać sygnały do dowolnego procesu. Zestaw wszystkich sygnałów daje polecenie kill -l Sygnały są ponumerowane od 1 do 30 kill -9 PID - SIGKILL SIKILL, SIGSTOP - nie moŝe być przechwycony przez proces i potraktowany inaczej SIGHUP - po zamknięciu sesji wszystkie procesy potomne procesu login dostają sygnał o numerze 1, powodujący ich przerwanie pod warunkiem, Ŝe nie przejmują tego sygnału i nie podejmują innego działania MoŜna uruchomić program odporny na ten sygnał np. przez nohup dowolny program
Sygnały #include<signal.h> fcja signal manipulowanie sygnałami SIG_IGN ignorowanie sygnału SIG_DFL przywraca domyślne działanie (równieŝ po przechwyceniu danego sygnału). void au(int sig) {printf( przechwytany sygnal %d\n,sig);} int main() { (void) signal(sigint,au);.. }
#include<signal.h> int raise(int sig); - do siebie #include<sys/types.h> #include<signal.h> int kill(pid_t pid, int sig); - do procesu o identycznym uid #include<unistd.h> unsigned int alarm(unsigned int sec); int pause(void) alarm: wysyła sygnał SIGALARM za sec sekund kaŝdy proces moŝe mieć max. 1 zaplanowany alarm pause wstrzymuje działanie programu do otrzymania sygnału sigaction interfejs obsługi sygnałów
Pliki - najczęstsza metoda komunikowania się procesów (jeden proces tworzy plik za pomocą dowolnego edytora, drugi przetwarza ten tekst porządkuje alfabetycznie) problem: proces czytający moŝe wyprzedzić proces piszący i uznać, Ŝe komunikacja została zakończona -> łącza komunikacyjne Łącza komunikacyjne nie są plikami chociaŝ mają swój i-węzeł nie ma dowiązania w systemie plików jeśli proces czytający zbyt wyprzedzi proces piszący -> oczekuje na dalsze dane; jeśli proces piszący zbyt wyprzedzi proces czytający -> zostaje uśpiony łącza komunikacyjne wykorzystywane z poziomu powłoki - potoki dotyczą procesów pokrewnych powolne
Kolejki FIFO łącza nazwane - kolejki FIFO (first-in-first-out) plik specjalny (typ pliku - p) moŝe być otwarty przez kaŝdy proces umoŝliwia współpracę wielu procesów piszących i czytających (gwarantują niepodzielność) powolne Semafory uniemoŝliwiają dostępu do zasobów dwóm lub większej liczbie procesów flaga moŝliwa do ustawiana i opuszczania przez róŝne procesy Komunikaty Procesy mogą przesłać do kolejki komunikatów niewielką ilość danych Procesy, które mają uprawnienia mogą pobierać z niej kolejki komunikaty
Pamięć dzielona najszybszy sposób komunikacji między procesami ten sam obszar pamięci jest przydzielany kilku procesom danych wygenerowane przez jeden proces są natychmiast dostępne dla innych procesów dostęp do pamięci dzielonej wymaga synchronizacji semafory
WĄTEK (proces lekki) NT W 95 pdst. jednostka wykorzystania procesora własne: LR, rejestry, stos wspólne: sekcja kodu, danych, otwarte pliki, sygnały przełączanie procesora między wątkami - tańsze od przełączania kontekstu między procesami ciężkimi procesy - reprezentują wykonywanie poszczególnych programów wątki - reprezentują oddzielne, współbieżne konteksty w ramach jednego procesu procesy - niezależne przestrzenie adresowe wątki - ta sama przestrzeń adresowa
Wątki w Linux ie Ta sama wewnętrzna reprezentacja jak dla procesu funkcja clone - tworzy nowy proces z odrębną tożsamością, dzielący struktury procesu rodzica struktura danych procesu - zawiera wskaźniki do: kontekstu systemu plików tablicy deskryptorów plików tablicy obsługi sygnałów kontekstu pamięci wirtualnej clone - nowa tożsamość i kontekst planowania, pozostałe konteksty mogą być wspólne lub skopiowane ( fork - szczególnym przypadkiem clone)
Wrażenie jednoczesnego wykonywania Szeregowanie asynchroniczne Istnieją wewnątrz procesów Program ->Proces -> wątek wykonujący sekwencyjnie program - > dodatkowe wątki (ten sam program, ten sam proces) Proces nie oddziałuje na proces rodzica kopiowanie pamięci wirtualnej, deskryptorów plików, innych zasobów Wątki współdzielą pamięć, deskryptory plików (np. exec kończy wszystkie wątki)
GNU/Linux Deklaracje funkcji obsługi wątków - <pthread.h> Dołączenie biblioteki libpthread -lpthread IDwątku - typ pthread_t Tworzenie wątku funkcja pthread_create Parametry: wskaźnik do IDwatku wskaźnik atrybutu (NULL - domyślne atrybuty) wskaźnik funkcji wątku argument typu void* Zwraca - wartość void* Kończenie wątku funkcja wątku kończy dzialanie funkcja pthread_exit funkcja pthread_cancel anulowanie Stany anulowalności wątku: asynchronicznie anulowalny synchronicznie anulowalny nie anulowalny
#include <pthread.h> #include <stdio.h> void* print_1(void* nic) { while (1) fputc( 1,stderr); return NULL; } main() { pthread_t idwatek; pthread_create(&idwatek, NULL, &print_1, NULL); while(1) fputc( 2, stderr); return 0; }
Przekazywanie danych do wątków przez argument wskaźnik do struktury zawierającej dane możliwość wykonywania tego samego kodu dla różnych danych przez wątki czekanie na zakończenie wątku (pthread_join) ID_watku funkcja pthread_self atrybuty wątku stan odłączenia dołączalny joinable nie jest czyszczony po zakończeniu działania (pthread_join) odłączony detached czyszczony po zakończeniu
Każdy wątek ma własny stos wywołań każdy wywoływany podprogram w każdym wątku ma własne zmienne lokalne przechowywane na stosie wątku Obszar danych własnych wątku: powielanie zmiennych dla wszystkich wątków każdy wątek ma swoją kopię tworzenie funkcja pthread_key_create ustawianie funkcja pthread_setspecific pobranie funkcja pthread_getspecific procedury czyszczące
SYNCHRONIZACJA WĄTKÓW eliminacja sytuacji wyścigu niepodzielne wykonywanie działań Muteksy (MUTual EXclusion locks) blokada, którą w danej chwili może zamknąć tylko jeden wątek muteks jest odblokowywany przez ten sam wątek próba zablokowania zablokowanego muteksa blokuje wątek po odblokowaniu jeden z czekających - przypadkowy wątek jest wznowiony może zablokować muteks możliwość zakleszczenia Dwukrotne zablokowanie muteksa przez jeden watek Szybki muteks deadlock RECOURCIVE_NP - rekurencyjny muteks zlicza blokady / nie wystąpi dedlock ERRORHECK_NP - nie można dwukrotnie zablokować muteksa - blad NP GNU/Linuks; nieprzenośne
SYNCHRONIZACJA WĄTKÓW muteksy testowanie muteksów bez blokowania Aby uniknąć czekania na zablokowanym muteksie funkcja pthread_mutex_trylock jeśli muteks nie jest zablokowany blokuje go jeśli jest zwraca kod błędu EBUSY
SYNCHRONIZACJA WĄTKÓW semafory zadanie: wątki przetwarzają zadania z kolejki rozwiązanie z muteksami: wątki pobierają zadania; jeśli kolejka pusta kończą się problem: kolejka opróżni się chwilowo; po nadejściu nowych zadań brak wątków potrzebny mechanizm blokujący wątki przy pustej kolejce zadań SEMAFOR funkcje: sem_init sem_wait sem_post sem_trywait sem_destroy sem_getvalue
SYNCHRONIZACJA WĄTKÓW zmienna warunku condition variable wątek działa w nieskończonej pętli sterowanej za pomocą flagi gdy flaga nie ustawiona wstrzymanie bez aktywnego oczekiwania zmienna warunku musi być ustawiona przez inny wątek po tym jak dany wątek rozpoczął czekanie na nią w przeciwnym razie sygnał utracony aby nie dopuścić do sytuacji wyścigu (wątek wywłaszczony po sprawdzeniu flagi) używane wspólnie z muteksami blokuj muteks testuj flagę if flaga ustawiona then zwolnij muteks; kontynuuj pracę else niepodzielnie zwolnij muteks i czekaj na zmianę warunku
Implementacja wątków w GNU/Linuks wątki realizowane jako procesy (getpid) nie otrzymują kopii, lecz współdzielą zasoby Sygnały sygnały wysyłane z zewnątrz programu odbierane zwykle przez główny wątek wątki mogą wysyłać sygnały do siebie pthread_kill
clone PROCESY A WĄTKI fork, pthread_create pozwala określać, które zasoby mają być współdzielone Procesy wątki Program RóŜne Ten sam Przestrzeń adresowa Kopia Wspólna moŝliwość uszkodzenia Koszty Większe - gdy pamięć zmieniana Współdzielenie IPC Podobne zadania