Procese si Fire de execuţie Linux

 

1.    Obiective

-          Înţelegerea structurii şi funcţionalităţii proceselor şi firelor de execuţie Linux;

-          constuirea şi manipularea proceselor Linux folosind limbajul C;

-          construire şi manipularea firelor de execuţie folosind limbajul C;

2.    Noţiuni teoretice

 

Ce este un proces ?

 

Un concept cheie în orice sistem de operare este procesul. Un proces este un program aflat în execuţie. Procesele sunt unitatea primitivă prin care sistemul de operare alocă resurse utilizatorilor.

 

În momentul lansării în execuţie a unui program executabil, în sistemul de operare se va crea un proces pentru alocarea resurselor necesare rulării programului respectiv. Fiecare sistem de operare pune la dispoziţie apeluri de sistem pentru:

-          crearea unui proces;

-          terminarea unui proces;

-          aşteptarea terminării unui proces;

-          apeluri pentru duplicarea descriptorilor de resurse între procese ori închiderea acestor descriptori;

 

Cum este identificat un proces în cadrul sistemul de operare ?

 

Fiecare proces este identificat în mod unic în cadrul Linux printr-un identificator unic numit Process ID (PID). Aceşti identificatori sunt asignaţi automat proceselor de către sistemul de operare în momentul în care un proces este construit.

 

Care sunt relaţiile între procese ?

 

Orice proces Linux are un părinte (cu excepţia procesului init ce are PID=1 şi este lansat automat în execuţie în momentul iniţializării sistemului de operare). Un proces care creează un  nou proces devine părintele acelui nou proces. Un proces poate avea mai multe procese fiu.

 

Comenzi utile Linux pentru manipularea proceselor

 

Comanda ps afişează lista proceselor aflate în execuţie la un moment dat în cadrul sistemului.

 

Comanda kill permite transmiterea semnalului de terminare a execuţiei pentru un proces.

 

% kill -9 pid

 

Comanda kill transmite de fapt către procesul cu pid-ul pid semnalul SIGTERM, care determină terminarea execuţie procesului. Comanda kill poate fi folosită pentru a trimite orice semnal către un proces. Se va reveni într-o lucrare următoare asupra semnalelor Linux.

 

Funcţii sistem pentru gestionarea proceselor

GCreare proceselor folosind funcţia fork

Funcţia fork creează un nou proces. Semnătura funcţiei este următoarea:

 

     #include <sys/types.h>
     #include <unistd.h>
 
     pid_t
     fork(void);

 

Pagina man asociată funcţie fork: http://www.hmug.org/man/2/fork.php.

 

La apelarea funcţiei fork, un proces nou este creat prin duplicarea procesului care a iniţiat apelul funcţiei fork. După crearea procesului nou, numit şi proces fiu, procesul iniţiator numit şi proces părinte va continua execuţia cu următoarea instrucţiune aflată după fork. Procesul fiu va executa acelaşi program începând cu aceiaşi instrucţiune de după funcţia fork.

 

Funcţia fork returneză pid-ul procesul fiu în cadrul procesului părinte, o în cadrul procesului fiu sau -1 în caz de eroare.

 

Având în vedere că procesul fiu va executa acelaşi program ca şi procesul părinte (începând cu instrucţiunea ce urmează instrucţiunii fork cu care a fost creat) se utilizează valoarea returnată de funcţia fork pentru a putea executa instrucţiuni diferite în procesul fiu şi în procesul părinte.

...
pid_t p = fork();
if(p==0){
  // instrucţiunile executate de procesul fiu 
}
else if(p>0){
  // instructiunile executate de procesul parinte
}
else{
  //mesa de eroare, procesul fiu nu a putu fi construit
}
 
...

FProcesul părinte şi procesul fiu sunt procese complet independente. Nu există nici o posibilitate de a modifica din cadrul unui proces fiu o variabilă dintr-un proces părinte, sau de a avea vizibilitatea asupra modificării valorilor variabilelor dintr-un proces în altul.

 

Pentru a comunica între procese sistemul de operare Linux pune la dispoziţia programatorului un set de mechanisme numit IPC (Inter Process Communication) ce va fi prezentat într-un alt capitol.

GFuncţilei getpid şi getppid pentru determinarea pid-ului unui proces.

Funcţia getpid returnează pid-ul procesului curent. Funcţia getppid returnează pid-ul procesului părinte. Semnăturile funcţiilor sunt:

 

     #include <sys/types.h>
     #include <unistd.h>
 
     pid_t
     getpid(void);
 
     pid_t
     getppid(void);

 

Pagina man asociată funcţiilor getpid şi getppid: http://www.hmug.org/man/2/getpid.php. 

 

GLansarea în execuţie a programelor folosind funcţiile de tip  exec.

În cadrul librăriilor sistem linux există definit un set de funcţii ce încep cu prefixul exec (execl, execv, execlp, execvp, execle şi execve) care sunt utilizate pentru a lansa în execuţie dintr-un proces un program. Semnătura funcţiei execve este dată în continuare (restul funcţiilor au semnături asemănătoare):

 

     #include <unistd.h>
 
     int
     execve(const char *path, char *const argv[], char *const envp[]);

 

Pagina man asociată funcţiei execve: http://www.hmug.org/man/2/execve.php. 

 

Spre deosebire de funcţia fork, care are ca efect construirea unui nou proces, funcţiile exec realizează înlocuirea procesului apelant cu un nou proces. Procesul nou are aceiaşi intrare în tabela de procese (acelaşi PID). Dacă apelul exec se desfăşoară normal, programul vechi este pierdut. Instrucţiunile ce urmează instrucţiunii exec nu se vor mai executa.

 

În mod uzual funcţiile exec se folosesc împreună cu funcţia fork pentru a crea procese copil şi a lansa în execuţie în cadrul acestora noi programe. Folosind această tehnică codul proceselor copil poate fi implementat în fişiere sursă diferite faţă de procesul părinte.         ...

pid_t child_pid = fork ();

if (child_pid == 0){

//procesul copil

execvp (program, arg_list);

fprintf (stderr, “eroare in execvp\n”);

abort ();

}

 

GTerminarea proceselor folosind funcţia exit.

Terminarea unui proces de către el însuşi se realizează prin apelul funcţie exit. Semnătura funcţiei este:

 

     #include <unistd.h>
 
     void
     exit(int status);

Pagina man asociată funcţiilor getpid şi getppid: http://www.hmug.org/man/2/_exit.php.

 

Dacă apelul funcţie exit lipseşte din program, aceasta este totuşi executată la revenirea din funcţia main.

 

GAşteptarea terminării proceselor folosind funcţiile wait şi waitpid

Funcţiile wait şi waitpid sunt folosite pentru a pune un proces părinte în aşteptare până când un proces fiu îşi termină activitatea.  Semnătura funcţiei este:

 

     #include <sys/types.h>
     #include <sys/wait.h>
 
     pid_t
     wait(int *status);
 
     pid_t
     waitpid(pid_t wpid, int *status, int options);
Pagina man asociată funcţiilor wait şi waitpid: http://www.hmug.org/man/2/wait.php. 

 

În unele situaţii este utilă punerea în aşteptare a unui proces părinte până când unul sau mai multe procese fiu îşi termină activitatea. În astfel de situaţii se folosesc funcţiile wait şi waitpid.

 

Funcţia wait pune în aşteptare procesul apelant până când unul dintre procesele fiu îşi termină execuţia. Funcţia waitpid pune în aşteptare procesul apelant până când un proces fiu cu un pid dat îşi termină activitatea.

 

Valoarea returnată de funcţia wait este pid-ul procesului fiu ce şi-a terminat execuţia. În variabila status este returnată o valoare ce semnifică cauza treminării procesului fiu. Dacă în momentul apelării funcţiei wait procesul nu avea nici un proces fiu atunci aceasta returnează valoarea -1.

3.    Desfăşurarea lucrării

Exercitiul 1.1. Compilaţi şi rulaţi aplicaţia exemplu_1. Rezolvaţi cerinţele din cadrul fişierului tema.

 

Exercitiul 1.2. Compilaţi şi rulaţi aplicaţia exemplu_2. Rezolvaţi cerinţele din cadrul fişierului tema.