Differences

This shows you the differences between two versions of the page.

Link to this comparison view

so:laboratoare:laborator-08 [2019/04/09 07:35]
bogdan.purcareata [Add useful links section]
so:laboratoare:laborator-08 [2022/05/02 17:25] (current)
daniel.dosaru [Tipuri de fire de execuție]
Line 1: Line 1:
-====== Laborator 08 - Thread-uri ​Linux ====== +====== Laborator 08 - Threaduri ​Linux ======
-===== Materiale ajutătoare ​=====+
  
-  *[[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab08-slides.pdf | lab08-slides.pdf]] 
-  *[[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab08-refcard.pdf | lab08-refcard.pdf]] 
  
 ==== Nice to read ==== ==== Nice to read ====
Line 25: Line 22:
 ===== Prezentare teoretică ===== ===== Prezentare teoretică =====
  
-În laboratoarele anterioare a fost prezentat conceptul de **proces**, acesta fiind unitatea elementară de alocare a resurselor utilizatorilor. În cadrul acestui laborator este prezentat conceptul de **fir de execuție** (sau **thread**),​ acesta fiind unitatea elementară de planificare într-un sistem. Ca și procesele, firele de execuție reprezintă un mecanism prin care un calculator poate sǎ ruleze mai multe task-uri simultan.+În laboratoarele anterioare a fost prezentat conceptul de **proces**, acesta fiind unitatea elementară de alocare a resurselor utilizatorilor. În cadrul acestui laborator este prezentat conceptul de **fir de execuție** (sau **thread**),​ acesta fiind unitatea elementară de planificare într-un sistem. Ca și procesele, firele de execuție reprezintă un mecanism prin care un calculator poate să ruleze mai multe task-uri simultan.
  
-Un fir de execuție există în cadrul unui proces, și reprezintă o unitate de execuție mai fină decât acesta. În momentul în care un proces este creat, în cadrul lui există un singur fir de execuție, care execută programul secvențial. Acest fir poate la rândul lui sǎ creeze alte fire de execuție; aceste fire vor rula porțiuni ale binarului asociat cu procesul curent, posibil aceleași cu firul inițial (care le-a creat).+Un fir de execuție există în cadrul unui proces, și reprezintă o unitate de execuție mai fină decât acesta. În momentul în care un proces este creat, în cadrul lui există un singur fir de execuție, care execută programul secvențial. Acest fir poate la rândul lui să creeze alte fire de execuție; aceste fire vor rula porțiuni ale binarului asociat cu procesul curent, posibil aceleași cu firul inițial (care le-a creat).
 ==== Diferențe dintre fire de execuție și procese ==== ==== Diferențe dintre fire de execuție și procese ====
  
Line 40: Line 37:
     *stivă     *stivă
     *set de registre (deci și un contor de program - registrul ''​(E)IP''​)     *set de registre (deci și un contor de program - registrul ''​(E)IP''​)
 +    *spaţiu de stocare local (EN: thread-local storage - [[https://​gcc.gnu.org/​onlinedocs/​gcc/​Thread-Local.html|TLS]])
  
 Procesele sunt folosite de SO pentru a grupa și aloca resurse, iar firele de execuție pentru a planifica execuția de cod care accesează (în mod partajat) aceste resurse. Procesele sunt folosite de SO pentru a grupa și aloca resurse, iar firele de execuție pentru a planifica execuția de cod care accesează (în mod partajat) aceste resurse.
Line 71: Line 69:
  
 __Dezavantaje__ : __Dezavantaje__ :
-  *comutarea contextului este efectuată de kernel (cu o viteză de comutare mai mică):+  *comutarea contextului este efectuată de kernel (cu o viteză de comutare mai mare):
     *se trece dintr-un fir de execuție în kernel     *se trece dintr-un fir de execuție în kernel
     *kernelul întoarce controlul unui alt fir de execuție.     *kernelul întoarce controlul unui alt fir de execuție.
Line 1024: Line 1022:
  
  
-====== Exerciţii ​de laborator ​======+====== Exerciţii ======
  
-===== Exercițiul 0 Joc interactiv =====+<note important>​ 
 +În cadrul laboratoarelor vom folosi repository-ul de git al materiei SO - https://​github.com/​systems-cs-pub-ro/​so. Va trebui sa clonați repository-ul pe masinile virtuale folosind comanda: ''​git clone https://​github.com/​systems-cs-pub-ro/​so''​. Dacă doriți să descărcați repositoryul în altă locație, folosiți comanda ''​git clone https://​github.com/​systems-cs-pub-ro/so ${target}''​.
  
-  * Detalii desfășurare [[http://​ocw.cs.pub.ro/courses/​so/​meta/​notare#​joc_interactiv|joc]].+Pentru a actualiza repository-ul,​ folosiți comanda ''​git pull origin master''​ din interiorul directorului în care se află repository-ulRecomandarea este să îl actualizați cât mai frecvent, înainte să începeți lucrul, pentru a vă asigura că aveți versiunea cea mai recentăÎn cazul în care gitul detectează conflicte la nivelul vreunui fişier, folosiți următoarele comenzi pentru a vă păstra modificările:​ 
 +<​code>​ 
 +git stash 
 +git pull origin master 
 +git stash pop 
 +</code>
  
-===== Linux =====+Pentru mai multe informații despre folosirea utilitarului git, urmați ghidul de la https://​gitimmersion.com. 
 +</​note>​
  
-În rezolvarea laboratorului folosiți arhiva de sarcini [[http://​elf.cs.pub.ro/so/​res/​laboratoare/​lab08-tasks.zip | lab08-tasks.zip]]+<note tip> 
 +Pentru a vă ajuta la implementarea exercițiilor din laborator, în directorul ''​utils''​ din arhivă există un fișier ''​utils.h''​ cu funcții utile. 
 +</note>
  
-<note tip> Pentru a vă ajuta la implementarea exercițiilor din laborator, în directorul ''​utils''​ din arhivă există un fișier ''​utils.h''​ cu funcții utile. </​note>​+===== Linux =====
  
 <​note>​Pentru a instala paginile de manual pentru '​pthreads'​ <​note>​Pentru a instala paginile de manual pentru '​pthreads'​
Line 1048: Line 1055:
 </​code> ​ </​code> ​
  
-Zonele de memorie cu dimensiunea de 8MB (8192KB) care se creează după fiecare apel ''​pthread_create''​ reprezintă noile //stive// alocate de către biblioteca ''​libpthread''​ pentru fiecare thread în parte. Observați că, în plus, se mai mapează ​de fiecare dată o pagină (4KB) cu protecția ''​%%---p%%''​ (PROT_NONE, private ​- vizibil în ''​procfs''​) care are rolul de %%"​%%pagină de gardă%%"​%%. ​+Zonele de memorie cu dimensiunea de 8MB (8192KB) care se creează după fiecare apel ''​pthread_create''​ reprezintă noile //stive// alocate de către biblioteca ''​libpthread''​ pentru fiecare thread în parte. Observați că, în plus, se mapează ​între paginile alocate stivelor thread-urilor (8192K) câte o pagină (4KB) cu protecția ''​%%----- [anon] ​%%''​ (PROT_NONE - vizibil în ''​procfs''​) care are rolul de %%"​%%pagină de gardă%%"​%%. ​
  
 Motivul pentru care nu se termină programul este prezența unui ''​​while(1)''​​ în funcția thread-urilor. Folosiți ''​Ctrl+C''​ pentru a termina programul. ​ Motivul pentru care nu se termină programul este prezența unui ''​​while(1)''​​ în funcția thread-urilor. Folosiți ''​Ctrl+C''​ pentru a termina programul. ​
Line 1062: Line 1069:
 </​code>​ </​code>​
  
-Verificați ce se întâmplă dacă la un moment dat un fir de execuție ​ moare (sau un proces, în funcție de ce executabil testați). Testați utilizând funcția ''​do_bad_task''​ la fiecare al 4-lea fir de execuție/​process.+Verificați ce se întâmplă dacă la un moment dat un fir de execuție moare (sau un proces, în funcție de ce executabil testați). Testați utilizând funcția ''​do_bad_task''​ la fiecare al 4-lea fir de execuție/​process. Observaţi cum încheierea anormală a unui thread duce la încheierea procesului din care face parte
  
-==== Exercițiul 3 - Thread safety ​====+==== Exercițiul 3 - Generator de numere pseudoaleatoare ​====
  
 <note important>​ <note important>​
-Datorită ​faptului că mașina virtuală ​''​spook'' ​are un singur core virtual, exercițiul următor trebuie realizat pe mașina fizică pentru a permite mai multor thread-uri să ruleze în același moment de timp.+Din cauza faptului că mașina virtuală are un singur core virtual, exercițiul următor trebuie realizat pe mașina fizică pentru a permite mai multor thread-uri să ruleze în același moment de timp.
 </​note>​ </​note>​
  
Line 1077: Line 1084:
 </​code>​ </​code>​
 </​note>​ </​note>​
-* ne vom concentra pentru rezolvarea TODO1 pe executabilui mutex 
  
-''​TODO 1'':​ Pentru a rezolva aceste doua conditii de cursa apelati functia increase_numbers intr-un mod thread_safe cu ajutor API-ului pus la dispozitie de critical.h+== Sincronizare acces variabile ==
  
-În fișierul ''​malloc.c''​ se creează ''​NUM_THREADS''​ thread-uri care alocă ​memorie în 1000 runde. Sunt șanse mari ca thread-urile să execute apeluri ''​malloc''​ concurente.  +Rezolvați comentariile ''​TODO1''​ din ''​malloc.c''​. Pentru a rezolva aceste două condiții de cursă apelați functia ''​increase_numbers''​ intr-un mod thread safe cu ajutor API-ului pus la dispozitie de ''​critical.h''​. De asemenea, sincronizați accesul în funcția ''​print_stats''​ (**de ce?**). 
-După ce a-ti rezolvat ''​TODO1'', ​compilati ​și rulati ​de mai multe ori. Observăm că programul rulează cu succes. Pentru a face verificări suplimentare,​ rulăm din nou ''​helgrind'':​+ 
 +Pentru testare, folosiți executabilul ''​mutex''​. 
 + 
 +În fișierul ''​malloc.c''​ se creează ''​NUM_THREADS''​ thread-uri care alocă ​o matrice de ''​NUM_ROWS X NUM_COLUMNS''​ întregi. Sunt șanse mari ca thread-urile să execute apeluri ''​malloc''​ concurente. 
 +  
 +După ce ați rezolvat ''​TODO1'', ​compilați ​și rulați ​de mai multe ori. Observăm că programul rulează cu succes. Pentru a face verificări suplimentare,​ rulăm din nou ''​helgrind'':​
  
 <code bash> <code bash>
Line 1088: Line 1099:
 </​code>​ </​code>​
  
-Observăm că nici ''​helgrind''​ nu raportează vreo eroare, lucru care conduce la faptul că funcția ''​malloc''​ ar fi thread-safe. (chiar daca acesta nu este protejat de API-ul pus la dispozitie+Observăm că nici ''​helgrind''​ nu raportează vreo eroare, lucru care conduce la faptul că funcția ''​malloc''​ ar fi thread-safe. (chiar daca acesta nu este protejat de API-ul pus la dispoziție)
 + 
 Pentru a putea fi siguri trebuie să consultăm paginile de manual și codul sursă. Pentru a putea fi siguri trebuie să consultăm paginile de manual și codul sursă.
  
Line 1096: Line 1108:
 Funcția ''​malloc''​ din implementarea GLIBC **este thread-safe**,​ lucru indicat în pagina de manual [[http://​man7.org/​linux/​man-pages/​man3/​malloc.3.html#​NOTES| malloc(3)]] (al treilea paragraf din secțiunea ''​NOTES''​) și vizibil în codul sursă prin prezența câmpului ''​mutex''​ în [[https://​sourceware.org/​git/?​p=glibc.git;​a=blob;​f=malloc/​malloc.c;​h=f361bad636167cf1680cb75b5098232c9232d771;​hb=HEAD#​l1672|structura malloc_state]]. Funcția ''​malloc''​ din implementarea GLIBC **este thread-safe**,​ lucru indicat în pagina de manual [[http://​man7.org/​linux/​man-pages/​man3/​malloc.3.html#​NOTES| malloc(3)]] (al treilea paragraf din secțiunea ''​NOTES''​) și vizibil în codul sursă prin prezența câmpului ''​mutex''​ în [[https://​sourceware.org/​git/?​p=glibc.git;​a=blob;​f=malloc/​malloc.c;​h=f361bad636167cf1680cb75b5098232c9232d771;​hb=HEAD#​l1672|structura malloc_state]].
 </​note>​ </​note>​
 +
 +== Spinlocks ==
  
 ''​TODO 2'':​ Implementati un spinlock folosindu-va de operatii atomice. ''​TODO 2'':​ Implementati un spinlock folosindu-va de operatii atomice.
 Operatiile atomice existente in standardul GCC le gasiti la [[https://​gcc.gnu.org/​onlinedocs/​gcc/​_005f_005fatomic-Builtins.html | __atomic functions]] Operatiile atomice existente in standardul GCC le gasiti la [[https://​gcc.gnu.org/​onlinedocs/​gcc/​_005f_005fatomic-Builtins.html | __atomic functions]]
  
-In fisierul critical.c trebuie sa completati in dreptul comentarilor asociate ''​TODO 2'',​ avand la dispozitie hint-uri.+In fisierul ​''​critical.c'' ​trebuie sa completati in dreptul comentarilor asociate ''​TODO 2'',​ avand la dispozitie hint-uri.
  
-Testati si rulati de mai multe ori, pentru a verifica consistenta variabilei globale: global_storage, executabilul ''​./spin''​.+Pentru testarefolosiți ​executabilul ''​spin''​. 
 + 
 +<​note>​ 
 +Aici, la verificarea corectitudinii nu vă mai poate ajuta ''​helgrind''​ pentru că nu are implementat suportul nativ. Există adnotări cu care poate fi ajutat să nu dea false positives, dar pentru asta e nevoie sa compilați și să linkați o versiune modificată de helgrind. Detalii [[http://​valgrind.org/​docs/​manual/​hg-manual.html|aici,​ secțiunea 7.5]]. 
 +</​note>​
 ==== Exercițiul 4 - Parallel fgrep ==== ==== Exercițiul 4 - Parallel fgrep ====
  
 <note important>​ <note important>​
-Datorită ​faptului că mașina virtuală ​''​spook'' ​are un singur core virtual, exercițiul următor trebuie realizat pe mașina fizică pentru a permite mai multor thread-uri să ruleze în același moment de timp.+Din cauza faptului că mașina virtuală are un singur core virtual, exercițiul următor trebuie realizat pe mașina fizică pentru a permite mai multor thread-uri să ruleze în același moment de timp.
 </​note>​ </​note>​
  
Line 1171: Line 1189:
 ==== BONUS ==== ==== BONUS ====
  
-=== 1 so karma - fork vs pthread_create ===+=== fork vs pthread_create ===
  
 Vrem să aflăm ce apeluri de sistem sunt realizate în urma apelurilor funcțiilor ''​fork''​ și ''​pthread_create''​. Vrem să aflăm ce apeluri de sistem sunt realizate în urma apelurilor funcțiilor ''​fork''​ și ''​pthread_create''​.
Line 1189: Line 1207:
 Observați alocarea unei stive separate pentru noul thread (argumentul ''​child_stack''​) cât și partajarea resurselor procesului cu acesta (''​flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND''​). Observați alocarea unei stive separate pentru noul thread (argumentul ''​child_stack''​) cât și partajarea resurselor procesului cu acesta (''​flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND''​).
  
-=== 1 so karma - Thread Specific Data ===+=== Thread Specific Data ===
  
 Fișierul ''​9-tsd/​tsd.c''​ conține o aplicație ce împarte un task între mai multe fire de execuție. Fiecare fir de execuție are un fișier de log în care va înregistra mesaje despre progresul său. Observați următoarele aspecte: Fișierul ''​9-tsd/​tsd.c''​ conține o aplicație ce împarte un task între mai multe fire de execuție. Fiecare fir de execuție are un fișier de log în care va înregistra mesaje despre progresul său. Observați următoarele aspecte:
Line 1198: Line 1216:
  
  
-=== 1 so karma - Mutex vs Spinlock ===+=== Mutex vs Spinlock ===
  
 Dorim să testăm care varianta este mai eficientă pentru a proteja incrementarea unei variabile. Dorim să testăm care varianta este mai eficientă pentru a proteja incrementarea unei variabile.
Line 1222: Line 1240:
  
 */ */
-===== Soluții ===== 
  
-[[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab08-sol.zip | lab08-sol.zip]] 
 ===== Resurse utile ===== ===== Resurse utile =====
  
so/laboratoare/laborator-08.1554784520.txt.gz · Last modified: 2019/04/09 07:35 by bogdan.purcareata
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0