Differences

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

Link to this comparison view

so:laboratoare:laborator-09 [2021/05/02 17:29]
teodor_stefan.dutu [Semafor Win32]
so:laboratoare:laborator-09 [2022/05/06 13:38] (current)
costin.carabas [Exercițiul 6 - Barrier]
Line 427: Line 427:
 Operația de decrementare se realizează doar cu o singură unitate (la fel ca în API-ul POSIX), în timp ce incrementarea se poate realiza cu orice valoare în limita maximă. Operația de decrementare se realizează doar cu o singură unitate (la fel ca în API-ul POSIX), în timp ce incrementarea se poate realiza cu orice valoare în limita maximă.
  
-==== Crearea și deschiderea ​====+=== Crearea și deschiderea ===
  
 Funcția de creare a semafoarelor este [[http://​msdn.microsoft.com/​en-us/​library/​ms682438(VS.85).aspx|CreateSemaphore]] și are sintaxa : Funcția de creare a semafoarelor este [[http://​msdn.microsoft.com/​en-us/​library/​ms682438(VS.85).aspx|CreateSemaphore]] și are sintaxa :
Line 450: Line 450:
 </​code>​ </​code>​
  
-==== Decrementarea (așteptarea) ​ ====+=== Decrementarea (așteptarea) ===
  
 Operația de decrementare a semaforului cu sau fără așteptare se realizează folosind una din funcțiile de așteptare. Cea mai des folosită este funcția [[http://​msdn.microsoft.com/​en-us/​library/​ms687032(VS.85).aspx|WaitForSingleObject]]. Operația de decrementare a semaforului cu sau fără așteptare se realizează folosind una din funcțiile de așteptare. Cea mai des folosită este funcția [[http://​msdn.microsoft.com/​en-us/​library/​ms687032(VS.85).aspx|WaitForSingleObject]].
  
-====  Incrementarea ​====+===  Incrementarea ===
  
 Incrementarea semaforului se realizează folosind funcția [[http://​msdn.microsoft.com/​en-us/​library/​ms685071(VS.85).aspx|ReleaseSemaphore]] cu sintaxa : Incrementarea semaforului se realizează folosind funcția [[http://​msdn.microsoft.com/​en-us/​library/​ms685071(VS.85).aspx|ReleaseSemaphore]] cu sintaxa :
Line 466: Line 466:
 </​code>​ </​code>​
  
-==== Distrugerea ​====+=== Distrugerea ===
  
 Operația de distrugere a unui semafor este similară cu cea de distrugere a unui mutex. Se folosește funcția [[http://​msdn.microsoft.com/​en-us/​library/​ms724211%28VS.85%29.aspx|CloseHandle]]. După ce toate ''​HANDLE''​-urile unui semafor au fost închise, semaforul este distrus și resursele ocupate de acesta eliberate. Operația de distrugere a unui semafor este similară cu cea de distrugere a unui mutex. Se folosește funcția [[http://​msdn.microsoft.com/​en-us/​library/​ms724211%28VS.85%29.aspx|CloseHandle]]. După ce toate ''​HANDLE''​-urile unui semafor au fost închise, semaforul este distrus și resursele ocupate de acesta eliberate.
Line 689: Line 689:
 ==== Adăugarea de taskuri la thread pool ==== ==== Adăugarea de taskuri la thread pool ====
  
-=== Așteptarea unei operații de intrare/​ieșire asincrone ​=== +<​spoiler>​ 
 +**Așteptarea unei operații de intrare/​ieșire asincrone**\\
 Pentru a adăuga la //thread pool// un task care se va executa la finalul unei operații de intrare/​ieșire asincrone pe un anumit //file handle//, se va apela funcția: Pentru a adăuga la //thread pool// un task care se va executa la finalul unei operații de intrare/​ieșire asincrone pe un anumit //file handle//, se va apela funcția:
  
Line 713: Line 713:
 </​code>​ </​code>​
  
-=== Adăugarea unui task pentru execuție imediată ​=== +**Adăugarea unui task pentru execuție imediată**\\
 Pentru a adăuga la //thread pool// un task care să fie executat imediat se va apela funcția: Pentru a adăuga la //thread pool// un task care să fie executat imediat se va apela funcția:
  
Line 728: Line 727:
 ); );
 </​code>​ </​code>​
 +</​spoiler>​
 ==== Timer Queues ==== ==== Timer Queues ====
  
Line 804: Line 804:
 </​code>​ </​code>​
 ==== Registered Wait Functions ==== ==== Registered Wait Functions ====
 +<​spoiler>​
 Funcțiile de așteptare înregistrate sunt funcții de așteptare executate de un fir de execuție din //thread pool//. În momentul în care obiectul de sincronizare după care se așteaptă trece în starea //​signaled//,​ se va executa rutina //​callback//​ asociată funcției de așteptare înregistrate,​ de un fir de execuție din //thread pool//. În mod implicit, funcțiile de așteptare înregistrate se **rearmează automat** și rutinele //​callback//​ sunt executate de fiecare dată când obiectul de sincronizare după care se așteaptă trece în starea **//​signaled//​**,​ sau intervalul de timeout **expiră**. Acest lucru se repetă până când înregistrarea funcției de așteptare este anulată. Se poate seta, însă, ca funcția de așteptare înregistrată să se execute **o singură dată**. Funcțiile de așteptare înregistrate sunt funcții de așteptare executate de un fir de execuție din //thread pool//. În momentul în care obiectul de sincronizare după care se așteaptă trece în starea //​signaled//,​ se va executa rutina //​callback//​ asociată funcției de așteptare înregistrate,​ de un fir de execuție din //thread pool//. În mod implicit, funcțiile de așteptare înregistrate se **rearmează automat** și rutinele //​callback//​ sunt executate de fiecare dată când obiectul de sincronizare după care se așteaptă trece în starea **//​signaled//​**,​ sau intervalul de timeout **expiră**. Acest lucru se repetă până când înregistrarea funcției de așteptare este anulată. Se poate seta, însă, ca funcția de așteptare înregistrată să se execute **o singură dată**.
  
-=== Înregistrarea unei funcții de așteptare ​=== +**Înregistrarea unei funcții de așteptare**\\
 Pentru înregistrarea în //thread pool// a unei funcții de așteptare se va apela funcția: Pentru înregistrarea în //thread pool// a unei funcții de așteptare se va apela funcția:
  
Line 835: Line 834:
 Prin intermediul parametrului ''​dwFlags''​ se pot transmite caracteristici ale firului de execuție care va executa rutina ''​Callback'',​ precum și dacă funcția de așteptare trebuie să se execute doar o singură dată. Funcția va întoarce, prin parametrul ''​phNewWaitObject'',​ un //handle// ce va fi folosit pentru deînregistrarea funcției de așteptare. Prin intermediul parametrului ''​dwFlags''​ se pot transmite caracteristici ale firului de execuție care va executa rutina ''​Callback'',​ precum și dacă funcția de așteptare trebuie să se execute doar o singură dată. Funcția va întoarce, prin parametrul ''​phNewWaitObject'',​ un //handle// ce va fi folosit pentru deînregistrarea funcției de așteptare.
  
-=== Deînregistrarea unei funcții de așteptare ​=== +**Deînregistrarea unei funcții de așteptare**\\
 Pentru a anula înregistrarea unei funcții de așteptare se va apela una dintre funcțiile: Pentru a anula înregistrarea unei funcții de așteptare se va apela una dintre funcțiile:
  
Line 847: Line 845:
  
 Funcția ''​UnregisterWaitEx''​ va semnaliza //​event//​-ul ''​CompletionEvent''​ în cazul în care se termină cu succes și rutina de //​callback//​ s-a terminat cu succes. Dacă valoarea lui ''​CompletionEvent''​ nu este ''​NULL'',​ atunci funcția va aștepta finalizarea operației de așteptare și terminarea rutinei asociate. ​ Funcția ''​UnregisterWaitEx''​ va semnaliza //​event//​-ul ''​CompletionEvent''​ în cazul în care se termină cu succes și rutina de //​callback//​ s-a terminat cu succes. Dacă valoarea lui ''​CompletionEvent''​ nu este ''​NULL'',​ atunci funcția va aștepta finalizarea operației de așteptare și terminarea rutinei asociate. ​
 +</​spoiler>​
 +====== Sumar ======
 +^  Operație ​ ^  POSIX  ^  Windows ​ ^
 +|  Crearea unui fir de execuție ​ |  ''​pthread_create'' ​ |  [[#​crearea_firelor_de_executie|CreateThread]] ​ |
 +|  Așteptarea unui fir de execuție ​ |  ''​pthread_join'' ​ |  [[#​asteptarea_firelor_de_executie|WaitForSingleObject]] ​ |
 +|  Crearea unui mutex  |  ''​pthread_mutex_init'' ​ |  [[#​crearea_si_deschiderea|CreateMutex]] ​ |
 +|  Obținerea unui mutex  |  ''​pthread_mutex_lock'' ​ |  [[#​obtinerea|WaitForSingleObject]] ​ |
 +|  Cedarea unui mutex  |  ''​pthread_mutex_unlock'' ​ |  [[#​cedarea|ReleaseMutex]] ​ |
 +|  Distrugerea unui mutex  |  ''​pthread_mutex_destroy'' ​ |  [[#​distrugerea|CloseHandle]] ​ |
 +|  Crearea unui semafor ​ |  ''​sem_init''/''​sem_open'' ​ |  [[#​crearea_si_deschiderea1|CreateSemaphore]] ​ |
 +|  Decrementarea unui semafor ​ |  ''​sem_wait'' ​ |  [[#​decrementarea_asteptarea|WaitForSingleObject]] ​ |
 +|  Incrementarea unui semafor ​ |  ''​sem_post'' ​ |  [[#​incrementarea|ReleaseSemaphore]] ​ |
 +|  Distrugerea unui semafor ​ |  ''​sem_destroy''/''​sem_close'' ​ |  [[#​distrugerea1|CloseHandle]] ​ |
 +|  Thread Local Storage ​ |  [[https://​gcc.gnu.org/​onlinedocs/​gcc/​Thread-Local.html|__thread]],​ [[https://​linux.die.net/​man/​3/​pthread_key_create|pthread_key_create]],​ [[https://​linux.die.net/​man/​3/​pthread_setspecific|pthread_setspecific]],​ [[https://​linux.die.net/​man/​3/​pthread_getspecific|pthread_getspecific]],​ [[https://​linux.die.net/​man/​3/​pthread_key_delete|pthread_key_delete]] ​ |  [[#​thread_local_storage|TlsAlloc,​ TlsSetValue,​ TlsGetValue, ​ TlsFree]] ​ |
  
-====== Exerciții de laborator ====== 
  
- +====== Exerciții ======
-===== Windows ​=====+
  
 <note important>​ <note important>​
Line 865: Line 875:
 Pentru mai multe informații despre folosirea utilitarului git, urmați ghidul de la https://​gitimmersion.com. Pentru mai multe informații despre folosirea utilitarului git, urmați ghidul de la https://​gitimmersion.com.
 </​note>​ </​note>​
 +
 +===== Windows =====
  
 <note tip> Pentru a deschide proiectul Visual Studio conținând exercițiile,​ deschideți fișierul lab09.sln. </​note>​ <note tip> Pentru a deschide proiectul Visual Studio conținând exercițiile,​ deschideți fișierul lab09.sln. </​note>​
Line 892: Line 904:
 În cadrul acestui exercițiu dorim să testăm diverse tipuri de incrementări atomice ale unei variabile, comparându-le timpul de execuție. Deschideți sursa ''​interlocked.c''​ din proiectul ''​3-interlocked''​. Programul crează ''​NO_THREADS''​ fire de execuție, care incrementează circular o variabilă (când se ajunge la o limită se resetează la 0). În cadrul acestui exercițiu dorim să testăm diverse tipuri de incrementări atomice ale unei variabile, comparându-le timpul de execuție. Deschideți sursa ''​interlocked.c''​ din proiectul ''​3-interlocked''​. Programul crează ''​NO_THREADS''​ fire de execuție, care incrementează circular o variabilă (când se ajunge la o limită se resetează la 0).
  
-Asigurați accesul exclusiv la variabila incrementată folosind [[#operatii atomice cu variabile partajate interlocked variable access | Interlocked Variables]] deoarece mecanismul e mai rapid decât o incrementare normală protejată cu ''​Mutex''​ sau ''​CRITICAL_SECTION''​ (folosiți funcția ''​InterlockedCompareExchange''​). Incrementarea circulară se va face în funcția ''​thread_function''​ (urmăriți comentariile cu // TODO 1 //). Veți avea nevoie de două operații interlocked (''​InterlockedIncrement''​ și ''​InterlockedCompareExchange''​).+Asigurați accesul exclusiv la variabila incrementată folosind [[#operatii atomice cu variabile partajate interlocked variable access | Interlocked Variables]] deoarece mecanismul e mai rapid decât o incrementare normală protejată cu ''​Mutex''​ sau ''​CRITICAL_SECTION''​ (folosiți funcția ''​InterlockedCompareExchange''​). Incrementarea circulară se va face în funcția ''​thread_function''​ (urmăriți comentariile cu //TODO 1//). Veți avea nevoie de două operații interlocked (''​InterlockedIncrement''​ și ''​InterlockedCompareExchange''​).
  
 Identificați o problemă cu folosirea ''​Interlocked Operations''​ pentru a incrementa circular o variabilă. Identificați o problemă cu folosirea ''​Interlocked Operations''​ pentru a incrementa circular o variabilă.
Line 920: Line 932:
 typedef struct { typedef struct {
  HANDLE hGuard;​  ​   /* mutex to protect internal variable access */  HANDLE hGuard;​  ​   /* mutex to protect internal variable access */
- HANDLE hEvent;​  ​   /* auto-resetable event */+ HANDLE hEvent;​  ​   /* manual ​resetable event */
  DWORD dwCount;​  ​   /* number of threads to have reached the barrier */  DWORD dwCount;​  ​   /* number of threads to have reached the barrier */
  DWORD dwThreshold; ​ /* barrier limit */  DWORD dwThreshold; ​ /* barrier limit */
Line 962: Line 974:
     * Implementați vizualizarea unui timer; spre exemplu, un fir de execuție care alternează două operații: draw și sleep. (desenează,​ se oprește, desenează, iar se oprește și tot așa; intervalul unei operații poate fi același)     * Implementați vizualizarea unui timer; spre exemplu, un fir de execuție care alternează două operații: draw și sleep. (desenează,​ se oprește, desenează, iar se oprește și tot așa; intervalul unei operații poate fi același)
 */ */
-===== Soluții ===== 
- 
- ​[[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab09-sol.zip | Soluţii laborator 9]] 
  
-~~NOCACHE~~ 
so/laboratoare/laborator-09.1619965785.txt.gz · Last modified: 2021/05/02 17:29 by teodor_stefan.dutu
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