This shows you the differences between two versions of the page.
patr:laboratoare:11 [2022/01/12 15:21] alexandru.ionita99 [Laboratorul 11 - Semafoare și Mutexuri] |
patr:laboratoare:11 [2022/01/13 14:04] (current) alexandru.ionita99 [Utilizare] |
||
---|---|---|---|
Line 2: | Line 2: | ||
==== Introducere ==== | ==== Introducere ==== | ||
- | FreeRTOS conține un API specializat în crearea și apelarea semafoarelor, denumit **Semaphore API**. După cum ați observat în cadrul laboratorului de C POSIX cu același subiect, semafoarele și mutexurile pot fi utilizate pentru sincronizarea task-urilor, accesul la resurse partajate, dar și alte tipuri de semnalizări (similar cu rolul semafoarelor fizice :) ). \\ | + | Dacă laboratorul trecut a fost destinat semafoarelor, cel de astăzi este dedicat mutexurilor. |
- | + | ||
- | FreeRTOS utilizează următoarele tipuri de semafoare, pe care le vom detalia în continuare: | + | |
- | * Semafoare binare | + | |
- | * Mutexuri | + | |
- | * Semafoare generalizate | + | |
Semafoarele binare și mutexurile sunt similare, dar prezintă două diferențe principale: | Semafoarele binare și mutexurile sunt similare, dar prezintă două diferențe principale: | ||
Line 18: | Line 13: | ||
În schimb, semafoarele binare blocate pot fi deblocate de orice alt task și nu există un mecanism de prioritizare. | În schimb, semafoarele binare blocate pot fi deblocate de orice alt task și nu există un mecanism de prioritizare. | ||
- | Toate tipurile de semafore, similar altor elemente din FreeRTOS, sunt referite cu ajutorul **handle-urilor**. În plus, pentru a le utiliza, este necesară declararea bilbiotecii **semphr.h**, alături de clasica **Arduino_FreeRTOS.h**. | + | Similar cu semafoarele, mutexurile sunt referite cu ajutorul **handle-urilor**. De asemenea, pentru a le utiliza, este necesară declararea bibliotecii **semphr.h**. |
<code c> | <code c> | ||
Line 28: | Line 23: | ||
// Declară o variabilă globală de tipul SemaphoreHandle_t | // Declară o variabilă globală de tipul SemaphoreHandle_t | ||
- | SemaphoreHandle_t semafor; | + | SemaphoreHandle_t mutex; |
</code> | </code> | ||
Line 35: | Line 30: | ||
==== Declarare ==== | ==== Declarare ==== | ||
- | === Semafoare binare === | + | După cum am specificat anterior, există câteva diferențe între semafoarele binare și mutexuri. Întrucât pot fi deblocate de orice task, semafoarele binare sunt mai potrivite atunci când avem nevoie de o sincronizare a două taskuri. \\ |
- | După cum am specificat anterior, există câteva diferențe între semafoarele binare și mutexuri. Întrucât pot fi deblocate de orice task, semafoarele binare sunt mai potrivite atunci când avem nevoie de o sincronizare a două taskuri. De exemplu, un task mai rapid poate fi blocat la un semafor până când un task mai lent ajunge într-un punct în care îl deblochează. \\ | + | Pe de altă parte, mutexurile sunt utilizate în principal pentru gestionarea accesului la o resursă partajată și sunt create cu ajutorul funcției **xSemaphoreCreateMutex()**, care alocă spațiu în heap. Dacă valoarea întoarsă este NULL, nu există suficientă memorie disponibilă. \\ |
- | + | ||
- | + | ||
- | Pentru a crea un semafor binar, este utilizată funcția ** xSemaphoreCreateBinary() **. Aceasta alocă spațiu în heap pentru semaforul binar și îl creează, cu starea inițială este "blocat". Dacă valoarea întoarsă este NULL, nu există suficientă memorie disponibilă. \\ | + | |
- | + | ||
- | ** Exemplu: ** | + | |
- | <code c> | + | |
- | SemaphoreHandle_t xSemaphore; | + | |
- | void vATask( void * pvParameters ) | + | |
- | { | + | |
- | /* Încearcă crearea unui semafor. */ | + | |
- | xSemaphore = xSemaphoreCreateBinary(); | + | |
- | if( xSemaphore == NULL ) | + | |
- | { | + | |
- | /* Nu există spațiu suficient în memorie pentru a crea semaforul */ | + | |
- | } | + | |
- | else | + | |
- | { | + | |
- | /* Semaforul poate fi acum utilizat. Apelarea xSemaphoreTake() va eșua până la apelarea xSemaphoreGive(). */ | + | |
- | } | + | |
- | } | + | |
- | </code> | + | |
- | + | ||
- | === Semafoare generalizate === | + | |
- | + | ||
- | Semafoarele generalizate pot avea orice valoare ≥ 0. Când valoarea sa este 0, semaforul este blocat. Pentru a crea un semafor generalizat, este utilizată funcția **xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )**. Primul argument reprezintă valoarea maximă a semaforului, iar al doilea argument definește valoare inițială a acestuia. | + | |
- | + | ||
- | **Exemplu** | + | |
- | <code c> | + | |
- | void vATask( void * pvParameters ) | + | |
- | { | + | |
- | SemaphoreHandle_t xSemaphore; // Declarare handle | + | |
- | + | ||
- | xSemaphore = xSemaphoreCreateCounting( 10, 0 ); // Creare semafor generalizat cu valoare inițială 0 și valoarea maximă 10 | + | |
- | if( xSemaphore != NULL ) | + | |
- | { | + | |
- | /* Semaforul a fost creat cu succces*/ | + | |
- | } | + | |
- | </code> | + | |
- | + | ||
- | În exemplul de mai sus, handle-ul a fost declarat în interiorul unui task și nu sub formă de variabilă globală. | + | |
- | === Mutexuri === | + | |
- | + | ||
- | Utilizate în principal pentru gestionarea accesului la o resursă partajată, mutexurile sunt create cu ajutorul funcției ** xSemaphoreCreateMutex()**. | + | |
**Exemplu:** | **Exemplu:** | ||
Line 103: | Line 55: | ||
==== Utilizare ==== | ==== Utilizare ==== | ||
- | Următoarele funcții sunt de interes: | + | Pentru a lucra cu mutexurile, se utilizează același funcții ca în cazul semafoarelor. Funcțiile de interes sunt: |
- | * Pentru a afla valoarea unui semafor, este utilizată funcția **UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore )** | + | |
- | * Pentru a crește valoarea unui semafor, este utilizată funcția **BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore )** | + | * **UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore )** - întoarce valoarea mutexului (0 sau 1) |
- | * Pentru a scădea valoarea unui semafor, este utilizată funcția **BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait)**. Al doilea parametru specifică timpul maxim pe care un task îl poate petrece așteptând deblocarea semaforului. După depășirea acestui timp, taksul își continuă execuția | + | * **BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore )** - eliberează mutexul |
- | * Pentru a șterge un semafor, este utilizată funcția **void vSemaphoreDelete( SemaphoreHandle_t xSemaphore )** | + | * **BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait)** - blochează mutexul. Al doilea parametru specifică timpul maxim pe care un task îl poate petrece așteptând deblocarea mutexului, dacă este deja blocat de un alt task. După depășirea acestui timp, taksul își continuă execuția |
+ | * **void vSemaphoreDelete( SemaphoreHandle_t xSemaphore )** - șterge mutexul referit prin handle | ||
<note tip>Funcțiile **Give** și **Take** întorc două valori posibile: **pdPASS** dacă operația a fost realizată cu succes sau **pdFAIL** dacă nu.</note> | <note tip>Funcțiile **Give** și **Take** întorc două valori posibile: **pdPASS** dacă operația a fost realizată cu succes sau **pdFAIL** dacă nu.</note> |