Rank: Membru Status: Posturi : 265 Reputatie : 6 Data de Inscriere : 29/07/2014
| Subiect: Tutorial Linux - PROCESE Mar Aug 19, 2014 3:40 pm |
|
| PROCESE IN LINUX
Daca dorim sa rezolvam o problema care se preteaza la o implementare cu mai multe procese, primul lucru pe care ar trebui sa-l stim este cum sa creem un nou proces.In Linux , modalitatea de a crea un nou proces este apelul functiei fork() , care se gaseste in bibliotecile "unistd.h" si "sys/types.h" ,acestea trebuind incluse daca vrem sa utilizam (cu succes) functia fork.
Prototipul arata cam asa: pid_t fork(void);
Ce se intampla dupa un apel fork: -se creaza un nou proces , prin copierea segmentelor de date si de cod ale procesului apelant; -functia intoarce in procesul tata PID-ul(process identifier) procesului nou creat; -functia intoarce in procesul fiu 0; -intoarce -1 in caz de eroare (adica nu s-a reusit crearea unui nou proces).
Sa urmarim un exemplu ca sa ne dam seama si mai bine ce se intampla. Programul urmator creaza un proces copil , dupa care fiecare proces isi tipareste PID-ul.Cod: - Cod:
-
#include #include #include
int main() { pid_t pid; int status;
//apelul fork() pid=fork();
switch(pid) { case 0: //aici ne aflam in procesul copil printf("PID fiu:%d\n",getpid()); return 0; break;
case -1: //eroare //ar fi bine daca s-ar face si tratarea erorii :) break; default: //aici ne aflam in procesul parinte
//asteptam intai sa se termine procesul copil wait(&status);
//tiparim mesajul printf("PID parinte:%d\n",getpid());
} return 0; }
Observatii: 1) Se vede ca in switch(pid) , cand ma aflu in procesul copil la sfarsitul sectiunii case corespunzatoare (case 0) folosesc inainte de break apelul return.Aceasta imi asigura ca dupa apelul fork procesul copil executa NUMAI ce se afla intre case 0: si apelul return , asigurand astfel terminarea procesului copil. Din cauza ca se copiaza zona de cod a procesului parinte in procesul fiu , dupa iesirea din switch() , ambele procese vor executa aceleasi instructiuni. In exemplul de fata , nu se mai executa decat return , deci s-ar fi putut si fara return la procesul copil. Daca programul ar contine o bucla in care se face un fork , daca procesul copil nu se termina , ar putea rezulta ceea ce se numeste un fork-bomb , programul generand la infinit noi procese , care vor provoca in cele din urma o blocare a sistemului de operare.
2)S-a folosit functia wait: pid_t wait(int *status); pentru a astepta terminarea procesului copil. Daca nu se face wait , procesele copil terminate vor fi inca prezente in sistemul de operare ca defuncte sau zombie. Daca vreti sa vedeti cum se manifesta asta faceti mai multe procese pe care nu le asteptati cu wait() si urmariti procesele pornite din sistem. Functia wait asteapta terminarea oricarui proces copil , dupa care in "status" se pot regasi informatii despre codul de return al procesului fiu si alte chestii interesante. Pentru a astepta terminarea unui anumit proces , se foloseste waitpid: pid_t waitpid(pid_t pid,int *status,int options); care asteapta terminarea procesului cu PID-ul pid. Pentru mai multe informatii consultati paginile man din Linux.
Pentru a intoarce PID-ul procesului curent avem functia: pid_t getpid(void); Pentru a intoarce PID-ul procesului parinte avem functia: pid_t getppid(void);
ATENTIE!!! Din cauza faptului ca dupa apelul fork se copiaza sectiunea de date a procesului parinte in procesul fiu , orice modificare asupra unei variabile declarata inainte de fork() intr-un proces nu va fi sesizata in celalalt proces. Daca explicatia de mai sus pare un pic imbarligata , sa luam un exemplu:
Declaram niste variabile: int a=0,b=10,status; pid_t pid;
pid=fork();
switch(pid) { case 0: a++; b--; return; break; case -1: break; default: wait(&status); a--; b++; } Greseala pe care eu am facut-o prima data cand am lucrat cu procese a fost ca avem impresia ca daca modific o variabila intr-un proces , si celalalt proces sesizeaza asta; din cauza copierii sectiunilor de date , fiecare proces lucreaza asupra propriilor variante ale fiecarei variabile , deci rezultatele operatiilor sunt independente. In urma executarii exemplului de mai sus , procesul parinte va avea a=-1 , b=11 in timp ce procesul copil va avea a=1 , b=9. Pentru ca procesele sa partajeze zone din sectiunea de date se poate folosi apelul clone (man clone pentru detalii).
Chiar daca in urma apelului fork nu se poate comunica direct intre procesele create, sistemul de operare pune la dispozitie o serie de mecanisme de comunicare interproces (pipe-uri , memorie partajata , semafoare , cozi de mesaje) , care vor fi detaliate pe parcursul tutorialelor de aici. |
|