Cursul 13 Fire de executie Semafoare Mutexuri Comunicarea

  • Slides: 33
Download presentation
Cursul 13 Fire de executie Semafoare Mutex-uri Comunicarea interprocese (popen si pclose)

Cursul 13 Fire de executie Semafoare Mutex-uri Comunicarea interprocese (popen si pclose)

 • • • Fire de executie Standardul Pthreads. Crearea şi terminarea firelor de

• • • Fire de executie Standardul Pthreads. Crearea şi terminarea firelor de execuţie Crearea unui fir de execuţie se realizează cu funcţia: #include <pthread. h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); Firul nou creat va executa codul din start_routine, căruia i se transmit argumentele arg. Noul fir de execuţie are atributele transmise prin attr sau atributele implicite dacă attr este NULL. Dacă pthread_create se execută cu succes, returnează 0, iar în thread se pune identificatorul firului nou creat. Posibile erori: – Procesul nu are resurse suficiente pentru noul fir, de ex. pentru că s-a depăşit numarul permis de fire. – Valoarea specificată pentru attr este nevalidă. De regulă prin attr se poate specifica dimensiunea stivei pentru noul fir. Frecvent se foloseşte însă valoarea NULL. Dacă identitatea firului nu este importantă, se poate folosi NULL şi pentru primul argument. În programele care folosesc fire de execuţie, există implicit un fir la pornirea programlui (firul principal) din care se face cel puţin primul apel pentru crearea unui nou fir. De regulă, firul principal este cel care la final aşteaptă terminarea tuturor celorlalte fire.

 • Terminarea execuţiei unui fir se specifică prin: void pthread_exit(void *status); • Starea

• Terminarea execuţiei unui fir se specifică prin: void pthread_exit(void *status); • Starea de terminare a firului se poate transmite prin locaţia de memorie status către apelantul unei alte funcţii, pthread_join. • Dacă apelul la pthread_exit nu este explicit, se va produce implicit un astfel de apel la terminarea codului firului. • Implicit firele se creează cu atributul de unificabil (joinable), dar pot fi şi detaşate, ceea ce înseamnă că eliberează la terminare memoria pe care au deţinut-o. Pentru firele unificabile se poate apela: int pthread_join(pthread_t thread, void **status); • Firul apelant îşi suspendă execuţia până la terminarea firului cu numele thread (efectul este nedefinit dacă thread este detaşabil sau dacă alt fir a apelat pthread_join pentru thread). Dacă status nu este NULL, indică spre argumentul de stare al lui pthread_exit. • Erori posibile: – dacă thread contine un pthread_join. – dacă thread este detaşat.

 • Exemplu: Acest program creaza un singur thread, partajeaza variabilele thread-ul original si

• Exemplu: Acest program creaza un singur thread, partajeaza variabilele thread-ul original si cere noului thread sa returneze un rezultat thread-ului original (thread 1. c): #include <stdio. h> #include <unistd. h> #include <stdlib. h> #include <pthread. h> void *thread_function(void *arg); char message[] = “Hello World”; int main() { int res; pthread_t a_thread; void *thread_result; res=pthread_create(&a_thread, NULL, thread_function, (void *) message); if (res != 0) { perror(“Thread creation failed”); exit(EXIT_FAILURE); } printf(“Waiting for thread to finish. . . n”);

res = pthread_join(a_thread, &thread_result); if (res != 0) { perror(“Thread join failed”); exit(EXIT_FAILURE); }

res = pthread_join(a_thread, &thread_result); if (res != 0) { perror(“Thread join failed”); exit(EXIT_FAILURE); } printf(“Thread joined, it returned %sn”, (char *)thread_result); printf(“Waiting for thread to finish. . . n”); res = pthread_join(a_thread, &thread_result); printf(“Message is now %sn”, message); exit(EXIT_SUCCESS); } void *thread_function(void *arg) { printf(“thread_function is running. Argument was %sn”, (char *)arg); sleep(3); strcpy(message, “Bye!”); pthread_exit(“Thank you for the CPU time”);

 • Ptr. a compila acest program, trebuie sa ne asiguram ca _REENTRANT este

• Ptr. a compila acest program, trebuie sa ne asiguram ca _REENTRANT este definita. • Ptr. a se asigura suportul ptr. executia thread-urilor sub Linux au fost elaborate mai multe proiecte; cel care este utilizat de variantele noi de Linux este NPTL(Native POSIX Thread Library). • In /usr/include/pthread. h se afla versiunea elaborata in 1996. Pentru a se obtine noi versiuni, trebuie instalat un RPM suplimentar care furnizeaza fisierele din /usr/include/nptl si /usr/lib/nptl. • Putem compila si link-edita programul prin: $ cc -D_REENTRANT -I/usr/include/nptl thread 1. c –o thread 1 -L/usr/lib/nptl –lpthread • Daca tastam: $. /thread 1 Waiting for thread to finish. . . thread_function is running. Argument was Hello World Thread joined, it returned Thank you for the CPU time Message is now Bye! • Cum lucreaza? Declaram un prototip ptr. functia pe care thread-ul o va apela cind va fi creat. void *thread_function(void *arg); • Asa cum este cerut de pthread_create, ea are ca unic arg. un pointer la void si returneaza tot un pointer la void.

 • In functia “main”, declaram niste variabile si apoi apelam pthread_create pentru a

• In functia “main”, declaram niste variabile si apoi apelam pthread_create pentru a incepe executia noului thread. pthread_t a_thread; void *thread_result; res = pthread_create(&a_thread, NULL, thread_function, (void *)message); • Transmitem adresa obiectului pthread_t pe care o putem folosi mai departe pentru a ne referi la thread. • Nu dorim sa modificam atributele implicite ale thread-ului, asa ca vom transmite NULL ca al doilea parametru. • Ultimii doi parametrii sunt functia apelata si parametrul care i se transmite. • Daca apelul se face cu succes, doua thread-uri se vor executa acum. Thread-ul original (main) continua si executa codul de dupa pthread_create si noul thread incepe executia, coresp. codului din thread_function.

 • Thread-ul original verifica daca noul thread a inceput si apoi apeleaza pthread_join.

• Thread-ul original verifica daca noul thread a inceput si apoi apeleaza pthread_join. res = pthread_join(a_thread, &thread_result); • Acum se transmite identificatorul thread-ului cu care asteapta sa se uneasca si un pointer la un rezultat. Aceasta functie va astepta pina cind un alt thread se termina inainte de retur. El apoi tipareste valoarea returnata din thread si continutul variabilei, si efectueaza iesirea. • Noul thread incepe executia si thread_function tipareste argumentele ei, “doarme” pentru o scurta perioada, actualizeaza variabilele globale, si apoi efectueaza iesirea, returnind un sir thread-ului principal. • Noul thread scrie mesajul in acelasi vector, la care acces thread-ul original.

Sincronizarea executiei proceselor • Metodele de comutare intre thread-uri prezentate anterior sunt ineficiente. In

Sincronizarea executiei proceselor • Metodele de comutare intre thread-uri prezentate anterior sunt ineficiente. In cele ce urmeaza, sunt prezentate alte metode de a controla executia thread-urilor si de a accesa sectiunile critice ale acestora. • Exista doua metode utilizate, bazate pe semafoare, respectiv pe mutexuri ( mutual exclusion). • Mutex –urile pot fi utilizate atunci cind se controleaza accesul thread-urilor la o zona de memorie partajata. • Semafoarele pot fi utilizate pentru a controla accesul la o multime de obiecte identice, privite ca un intreg (de exemplu, o centrala telefonica cu mai multe linii). • Sincronizarea cu semafoare. Semaforul este considerat în Pthreads o variabilă cu valori de tip întreg, partajată între firele de execuţie (generalizare a mutex-ului). • Operaţii principale asupra semafoarelor: - incrementarea atomică şi aşteptarea ca semaforul să aibă o valoare nenegativă; - decrementarea atomică. • Conceptul de semafor nu este strict necesar (se pot folosi numai mutexuri), dar simplifică programarea în unele situaţii • Prezenţa facilităţilor pentru semafoare se recunoaşte căutând fişierul antet semaphore. h, in care se găsesc prototipuri ale funcţiilor prezentate in continuare.

 • Crearea unui semafor se face cu functia sem_init, al carei sablon este:

• Crearea unui semafor se face cu functia sem_init, al carei sablon este: #include <semaphore. h> int sem_init(sem_t *sem, int pshared, unsigned int value); • Aceasta functie initializeaza un obiect semafor, catre care puncteaza sem. Prin argumentul pshared se indică dacă semaforul este local procesului (0) sau poate fi partajat cu alte procese. Implementarea din Linux nu permite partajarea. Value este valoarea semaforului. • Urmatoarea pereche de functii controleaza valoarea semaforului; sintaxa lor este: #include <semaphore. h> int sem_wait(sem_t *sem); int sem_post(sem_t *sem); • Funcţia sem_post incrementează atomic valoarea curentă a semaforului. Atomic inseamna ca doua thread-uri realiz. op. indep. unul fata de altul. Nu blocheaza niciodată firul apelant şi poate fi folosită la tratarea semnalelor. • Functia sem_wait decrementeaza atomic valoarea semaforului, asteptind pina cind acesta are o valoare nenula (a fost incrementat de alte semafoare).

 • La sem_trywait, dacă valoarea semaforului este 0 se revine cu eroare. •

• La sem_trywait, dacă valoarea semaforului este 0 se revine cu eroare. • Funcţia sem_destroy distruge un semafor, eliberând resursele deţinute de acesta. Se presupune că în momentul apelului nu există fire în aşteptare la semafor. • Sintaxa lor este: #include <semaphore. h> int sem_trywait(sem_t *sem); int sem_destroy (sem_t *sem); • Exemplu: Acest program (thread 3. c), se bazeaza pe thread 1. c. #include <stdio. h> #include <unistd. h> #include <stdlib. h> #include <string. h> #include <pthread. h> #include <semaphore. h> void *thread_function(void *arg); sem_t bin_sem; #define WORK_SIZE 1024 char work_area[WORK_SIZE];

int main() { int res; pthread_t a_thread; void *thread_result; res = sem_init(&bin_sem, 0, 0);

int main() { int res; pthread_t a_thread; void *thread_result; res = sem_init(&bin_sem, 0, 0); if (res != 0) { perror(“Semaphore initialization failed”); exit(EXIT_FAILURE); } res = pthread_create(&a_thread, NULL, thread_function, NULL); if (res != 0) { perror(“Thread creation failed”); exit(EXIT_FAILURE); } printf(“Input some text. Enter ‘end’ to finishn”); while(strncmp(“end”, work_area, 3) != 0) {fgets(work_area, WORK_SIZE, stdin); sem_post(&bin_sem); }

printf(“n. Waiting for thread to finish. . . n”); res = pthread_join(a_thread, &thread_result); if

printf(“n. Waiting for thread to finish. . . n”); res = pthread_join(a_thread, &thread_result); if (res != 0) { perror(“Thread join failed”); exit(EXIT_FAILURE); } printf(“Thread joinedn”); sem_destroy(&bin_sem); exit(EXIT_SUCCESS); } void *thread_function(void *arg) { sem_wait(&bin_sem); while(strncmp(“end”, work_area, 3) != 0) { printf(“You input %d charactersn”, strlen(work_area) -1); sem_wait(&bin_sem); } pthread_exit(NULL); }

 • Observatii. • 1. Prima schimbare importanta este includerea lui semaphore. h pt.

• Observatii. • 1. Prima schimbare importanta este includerea lui semaphore. h pt. a putea acesa functiile de lucru cu semafoare. Apoi vom declara un semafor si anumite variabile si initializam semaforul inainte de a crea noul thread. sem_t bin_sem; #define WORK_SIZE 1024 char work_area[WORK_SIZE]; int main() { int res; pthread_t a_thread; void *thread_result; res = sem_init(&bin_sem, 0, 0); if (res != 0) { perror(“Semaphore initialization failed”); exit(EXIT_FAILURE); } • Observam ca am setat valoarea initiala a semaforului cu 0.

 • 2. In functia principala, dupa lansarea noului thread, se citeste un text

• 2. In functia principala, dupa lansarea noului thread, se citeste un text de la tastatura, se incarca work_area si apoi se incrementeaza semaforul sem_post. printf(“Inputsome text. Enter ‘end’ to finishn”); while(strncmp(“end”, work_area, 3) != 0) { fgets(work_area, WORK_SIZE, stdin); sem_post(&bin_sem); } • 3. In noul thread, se asteapta la semafor si apoi se contorizeaza caracterele de la intrare. sem_wait(&bin_sem); while(strncmp(“end”, work_area, 3) != 0) { printf(“You input %d charactersn”, strlen(work_area) -1); sem_wait(&bin_sem); } • 3. Atita timp cit semaforul este setat, se asteapta intrarea de la tastatura. Cind avem o anumita intrare, se elibereaza semaforul, si astfel se permite celui de-al doilea thread sa contorizeze caracterele, inainte ca primul thread sa citeasca din nou de la tastatura.

 • 4. Ambele thread-uri partajeaza vectorul work_area. • Compilarea si editarea de legaturi

• 4. Ambele thread-uri partajeaza vectorul work_area. • Compilarea si editarea de legaturi se face cu: $ cc -D_REENTRANT -I/usr/include/nptl thread 3. c –o thread 3 -L/usr/lib/nptl -lpthread $. /thread 3 Input some text. Enter ‘end’ to finish The Wasp Factory You input 16 characters Iain Banks You input 10 characters end Waiting for thread to finish. . . Thread joined • 5. Cum lucreaza. Cind initializam semaforul, acesta este setat la valoarea 0. Astfel, cind se lanseaza functia thread-ului, apelul sem_wait produce blocarea si asteptarea pina cind valoarea semaforului devine nenula. In thread-ul principal, se asteapta pina cind avem un text si apoi se incrementeaza semaforul cu sem_post, care permite imediat altui thread sa revina din propriul sem_wait si sa inceapa executia. Odata ce a numarat caracterele, el apeleaza din nou sem_wait si este blocat pina cind thread-ul principal apeleaza din nou sem_post pt. a incrementa semaforul.

 • • Funcţii pentru excluderea mutuală Pentru protejarea accesului la secţiunile critice în

• • Funcţii pentru excluderea mutuală Pentru protejarea accesului la secţiunile critice în Pthreads se prevăd entităţi numite mutex - semafoare binare. Iniţializarea unui mutex: int pthread_mutex_init(pthread_mutex_t *mutx, const pthread_mutex_attr *attr); Se creează un nou mutex, cu atributele specificate sau implicite. Utilizarea funcţiei nu este absolut necesară, se face o iniţializare implicită când un mutex este declarat într-un program. Blocarea unui mutex: int pthread_mutex_lock(pthread_mutex_t *mutx); Dacă funcţia găseşte mutx deja blocat, firul curent intră în aşteptare până când mutx este deblocat de alt fir. Blocarea cu testarea valorii mutex-ului, permite ca firul curent să nu fie pus în aşteptare: int pthread_mutex_trylock(pthread_mutex_t *mutx); Dacă mutx este liber în momentul apelului, el va fi blocat, iar funcţia returnează 0. În caz contrar se revine imediat din funcţie, cu eroare. Deblocarea unui mutex se realizează cu funcţia: int pthread_mutex_unlock(pthread_mutex_t *mutx); Dacă firul curent este momentan proprietarul lui mutx, acesta este deblocat. Dacă există fire în aşteptare la mutx, atunci planificatorul de fire va selecta un fir care obţine mutx, altfel mutx rămâne disponibil (deblocat).

 • Exemplu: Programul thread 4. c se obtine prin modificarea lui thread 1.

• Exemplu: Programul thread 4. c se obtine prin modificarea lui thread 1. c prin utilizarea mutex-urilor; thread-urile acceseaza variabilele critice in excludere mutuala. #include <stdio. h> #include <unistd. h> #include <stdlib. h> #include <string. h> #include <pthread. h> #include <semaphore. h> void *thread_function(void *arg); pthread_mutex_t work_mutex; /*prot. both work_area and time_to_exit */ #define WORK_SIZE 1024 char work_area[WORK_SIZE]; int time_to_exit=0;

int main() { int res; pthread_t a_thread; void *thread_result; res=pthread_mutex_init(&work_mutex, NULL); if (res !=0)

int main() { int res; pthread_t a_thread; void *thread_result; res=pthread_mutex_init(&work_mutex, NULL); if (res !=0) { perror(“Mutex initialization failed”); exit(EXIT_FAILURE); } res=pthread_create(&a_thread, NULL, thread_function, NULL ); if (res !=0) { perror(“Thread creation failed”); exit(EXIT_FAILURE); } pthread_mutex_lock(&work_mutex); printf(“Input some text. Enter ‘end’ to finishn”);

while(!time_to_exit) { fgets(work_area, WORK_SIZE, stdin); pthread_mutex_unlock(&work_mutex); while(1) { pthread_mutex_lock(&work_mutex); if (work_area[0]!= ‘�’) { pthread_mutex_unlock(&work_mutex);

while(!time_to_exit) { fgets(work_area, WORK_SIZE, stdin); pthread_mutex_unlock(&work_mutex); while(1) { pthread_mutex_lock(&work_mutex); if (work_area[0]!= ‘’) { pthread_mutex_unlock(&work_mutex); sleep(1); } else { break; } } } pthread_mutex_unlock(&work_mutex); printf(“n. Waiting for thread to finish. . . n”); res = pthread_join(a_thread, &thread_result); if (res != 0) { perror(“Thread join failed”); exit(EXIT_FAILURE); }

printf(“Thread joinedn”); pthread_mutex_destroy(&work_mutex); exit(EXIT_SUCCESS); } void *thread_function(void *arg) { sleep(1); pthread_mutex_lock(&work_mutex); while(strncmp(“end”, work_area, 3)

printf(“Thread joinedn”); pthread_mutex_destroy(&work_mutex); exit(EXIT_SUCCESS); } void *thread_function(void *arg) { sleep(1); pthread_mutex_lock(&work_mutex); while(strncmp(“end”, work_area, 3) != 0) { printf(“You input %d charactersn”, strlen(work_area)-1; work_area[0] = ‘’; pthread_mutex_unlock(&work_mutex); sleep(1); pthread_mutex_lock(&work_mutex); while (work_area[0] == ‘’ ) { pthread_mutex_unlock(&work_mutex); sleep(1); pthread_mutex_lock(&work_mutex); }} time_to_exit = 1; work_area[0] = ‘’; pthread_mutex_unlock(&work_mutex); pthread_exit(0); }

 • Compilarea se face cu: $ cc -D_REENTRANT -I/usr/include/nptl thread 4. c –o

• Compilarea se face cu: $ cc -D_REENTRANT -I/usr/include/nptl thread 4. c –o thread 4 -L/usr/lib/nptl -lpthread • Dupa ce se tasteaza: $. /thread 4 • Se afiseaza: Input some text. Enter ‘end’ to finish Whit You input 4 characters The Crow Road You input 13 characters end Waiting for thread to finish. . . Thread joined • Cum lucreaza. Mai intii se declara un mutex, variabilele work_area si time_to_exit. pthread_mutex_t work_mutex; /* protects both work_area and time_to_exit */ #define WORK_SIZE 1024 char work_area[WORK_SIZE]; int time_to_exit = 0;

 • Urmeaza initializarea mutex-ului. res = pthread_mutex_init(&work_mutex, NULL); if (res != 0) {perror(“Mutex

• Urmeaza initializarea mutex-ului. res = pthread_mutex_init(&work_mutex, NULL); if (res != 0) {perror(“Mutex initialization failed”); exit(EXIT_FAILURE); } • Dupa aceasta, se incepe noul thread, al carui cod este: pthread_mutex_lock(&work_mutex); while(strncmp(“end”, work_area, 3) != 0) { printf(“You input %d charactersn”, strlen(work_area)-1); work_area[0] = ‘’; pthread_mutex_unlock(&work_mutex); sleep(1); pthread_mutex_lock(&work_mutex); while (work_area[0] == ‘’ ) { pthread_mutex_unlock(&work_mutex); sleep(1); pthread_mutex_lock(&work_mutex); }} time_to_exit = 1; work_area[0] = ‘’; pthread_mutex_unlock(&work_mutex);

 • Mai intii noul thread incearca sa inchida mutex-ul. Daca este deja incuiat,

• Mai intii noul thread incearca sa inchida mutex-ul. Daca este deja incuiat, apelul se va bloca pina cind mutex-ul se va elibera. • Odata ce are acces, verifica sa vada daca exista o cerere de iesire. In caz afirmativ, se seteaza time_to_exit, initializeaza primul caracter al lui work_area, si iese. • Daca nu vrea sa iasa, contorizeaza caracterele si apoi seteaza primul caracter cu “null” (aceasta setare este folosita pentru a se arata terminarea numararii). • Apoi se inchide mutex-ul si se asteapta executia threadului principal. • Periodic se incearca inchiderea mutex-ului, si cind se realizeaza se verifica daca thread-ul principal ne-a furnizat inf. despre cum a lucrat.

 • Codul thread-ului principal este: pthread_mutex_lock(&work_mutex); printf(“Input some text. Enter ‘end’ to finishn”);

• Codul thread-ului principal este: pthread_mutex_lock(&work_mutex); printf(“Input some text. Enter ‘end’ to finishn”); while(!time_to_exit) { fgets(work_area, WORK_SIZE, stdin); pthread_mutex_unlock(&work_mutex); while(1) { pthread_mutex_lock(&work_mutex); if (work_area[0] != ‘’) { pthread_mutex_unlock(&work_mutex); sleep(1); } else { break; } } } pthread_mutex_unlock(&work_mutex);

Comunicarea interprocese prin Pipe • Funcţiile popen şi pclose • Sintaxa lor este: FILE

Comunicarea interprocese prin Pipe • Funcţiile popen şi pclose • Sintaxa lor este: FILE *popen(const char *cmdstring, const char *type); int pclose(FILE *fp); • Funcţia popen permite unui program să invoce un alt program ca un nou proces şi fie să-i transmita date, fie sa primeasca date de la el. • Funcţia popen apelează fork, după care apelează exec pentru a lansa cmdstring şi returnează un pointer de fişier. • Dacă argumentul type este ˝r˝, pointerul de fişier este conectat la ieşirea standard a lui cmdstring (datele de ieşire din programul cmdstring sunt puse la dispoziţia programului care il invocă) ; dacă type este ˝w˝, pointerul de fişier este conectat la intrarea standard a lui cmdstring (datele de ieşire din program sunt puse la dispoziţia programului cmdstring) • Funcţia pclose închide fluxul standard de I/E, aşteaptă terminarea comenzii lansate prin popen şi în final returnează shell-ului starea de terminare

 • Exemplu. Citirea iesirii de la un program extern(popen 1. c). Vom folosi

• Exemplu. Citirea iesirii de la un program extern(popen 1. c). Vom folosi popen pt. a accesa informatii de la comanda uname. Comanda uname -a afiseaza informatii de sistem (tipul masinii, numele SO, versiunea, numele de retea al masinii etc. ). • Dupa initializari, se deschide pipe-ul la uname, facindu-l citibil si se seteaza read_fp ptr. a puncta la iesire. La sfirsit, pipe-ul referentiat prin read_fp este inchis. #include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> int main() { FILE *read_fp; char buffer[BUFSIZ + 1]; int chars_read; memset(buffer, ‘’, sizeof(buffer)); read_fp = popen(“uname -a”, “r”);

if (read_fp != NULL) { chars_read=fread(buffer, sizeof(char), BUFSIZ, read_fp); if (chars_read > 0) {

if (read_fp != NULL) { chars_read=fread(buffer, sizeof(char), BUFSIZ, read_fp); if (chars_read > 0) { printf(“Output was: -n%sn”, buffer); } pclose(read_fp); exit(EXIT_SUCCESS); } exit(EXIT_FAILURE); } • Daca tastam $. /popen 1 • Iesirea este: Output was: Linux gw 1 2. 4. 20 -8 #1 Thu Mar 13 17: 54: 28 EST 2003 i 686 i 386 GNU/Linux • Obs. Programul foloseste apelul popen pt. a invoca comanda uname cu parametrul -a. Apoi foloseste fluxul returnat pt. a citi date (pina la BUFSIZ caractere) si le tipareste pe ecran.

 • Exemplu: Transmiterea iesirii unui alt program. Vom folosi com. od –c, care

• Exemplu: Transmiterea iesirii unui alt program. Vom folosi com. od –c, care afiseaza continutul unui fisier. #include <unistd. h> #include <stdlib. h> #include <stdio. h> int main() { FILE *write_fp; char buffer[BUFSIZ + 1]; sprintf(buffer, “Once upon a time, there was. . . n”); write_fp = popen(“od -c”, “w”); if (write_fp != NULL) { fwrite(buffer, sizeof(char), strlen(buffer), write_fp); pclose(write_fp); exit(EXIT_SUCCESS); } exit(EXIT_FAILURE); } • Când vom rula acest program, vom obtine urmatoarea iesire: $. /popen 2 0000000 O n c e u p o n a t i m e 0000020 , t h e r e w a s. . . n 0000037

 • Cum funcţionează? Pentru a porni comanda od –c, programul foloseste popen cu

• Cum funcţionează? Pentru a porni comanda od –c, programul foloseste popen cu parametrul "w", astfel încât să poată trimite datele la acea comanda. • Acesta trimite apoi un şir de caractere, pe care od -c le primeşte şi le proceseaza; apoi afisează rezultatul prelucrării la iesirea standard. • Din linia de comandă, putem obţine aceleiaşi ieşiri cu comanda $echo “Once upon a time, there was. . . ” | od –c • Transmiterea mai multor date. Mecanismul pe care l-am folosit până acum, trimite sau primeste toate datele dintr-un singur fread sau fwrite. Se pune problema prelucrarii unui volum mai mare de date. Pentru a nu se utiliza un buffer de dimensiune mare, vom putea utiliza mai multe apeluri fread sau fwrite Urmatorul exemplu (popen 3. c), citeste toate datele dintr-o conducta. În acest program, citim datele de iesire ale comenzii ps -alx. Nu există nici o modalitate de a şti în avans cât de multe ieşiri vor fi, deci trebuie să se permită mai multe citiri din pipe. #include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h>

int main() { FILE *read_fp; char buffer[BUFSIZ + 1]; int chars_read; memset(buffer, ‘�’, sizeof(buffer));

int main() { FILE *read_fp; char buffer[BUFSIZ + 1]; int chars_read; memset(buffer, ‘’, sizeof(buffer)); read_fp = popen(“ps -ax”, “r”); if (read_fp != NULL) {chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp); while (chars_read > 0) { buffer[chars_read – 1] = ‘’; printf(“Reading: - n %sn”, buffer); chars_read=fread(buffer, sizeof(char), BUFSIZ, read_fp); } pclose(read_fp); exit(EXIT_SUCCESS); } exit(EXIT_FAILURE); }

$. /popen 3 Reading: PID TTY STAT TIME COMMAND 1 ? S 0: 04

$. /popen 3 Reading: PID TTY STAT TIME COMMAND 1 ? S 0: 04 init 2 ? SW 0: 00 [kflushd] 3 ? SW 0: 00 [kpiod] 4 ? SW 0: 00 [kswapd] 5 ? SW< 0: 00 [mdrecoveryd]. . . 240 tty 2 S 0: 02 emacs draft 1. txt Reading: 368 tty 1 S 0: 00. /popen 3 369 tty 1 R 0: 00 ps -ax. . .

 • Cum funcţionează. • Programul foloseste popen cu un parametru "r" într -un

• Cum funcţionează. • Programul foloseste popen cu un parametru "r" într -un mod similar cu popen 1. c. • De această dată, se continuă citirea din fluxul de iesire, până când nu mai există date disponibile. • Observam că, deşi comanda ps are o durata mai lunga de executie, Linux le planifica, astfel încât ambele programe se execută atunci când lucrul acesta este posibil. • În cazul în care procesul cititor ( popen 3 ), nu dispune de date de intrare, este suspendat până exista date disponibile. • În cazul în care procesul scriitor (ps), produce mai multe date decit capacitatea tamponului, este suspendat până când cititorul a consumat unele dintre aceste date.