pthread_cond_init(3)

NUME
pthread_cond_init, pthread_cond_signal, pthread_cond_broadcast, pthread_cond_wait, pthread_cond_timedwait, pthread_cond_destroy - operații asupra condițiilor

SINOPSIS
#include <pthread.h>

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int pthread_cond_init(pthread_cond_t *cond,
                      pthread_condattr_t *cond_attr);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
                      const struct timespec *abstime);
int pthread_cond_destroy(pthread_cond_t *cond);

DESCRIERE
O condiție (prescurtare de la „variabilă de condiție”) este un mecanism de sincronizare care permite firelor de execuție să suspende execuția și să cedeze procesoarele până când este satisfăcută o anumită condiție (un predicat) privind datele partajate. Operațiile de bază ale condițiilor sunt: semnalizarea condiției (când predicatul devine adevărat) și așteptarea condiției, suspendând execuția firului până când un alt fir semnalizează condiția.

O variabilă de condiție trebuie să fie întotdeauna asociată cu un mutex, pentru a evita condiția de „competiție pentru obținerea de date” în care un fir se pregătește să aștepte pe o variabilă de condiție și un alt fir semnalizează condiția chiar înainte ca primul fir să aștepte efectiv pe ea.

pthread_cond_init() inițializează variabila de condiție cond, utilizând atributele de condiție specificate în cond_attr sau atributele implicite dacă cond_attr este NULL. Implementarea „LinuxThreads” nu acceptă atribute pentru condiții, prin urmare parametrul cond_attr este de fapt ignorat.

Variabilele de tip pthread_cond_t pot fi, de asemenea, inițializate static, utilizând constanta PTHREAD_COND_INITIALIZER.

pthread_cond_signal() repornește unul dintre firele care așteaptă variabila de condiție cond. În cazul în care niciun fir de execuție nu așteaptă pe cond, nu se întâmplă nimic. În cazul în care mai multe fire așteaptă pe cond, se repornește exact unul dintre ele, dar nu se specifică care.

pthread_cond_broadcast() repornește toate firele care așteaptă variabila de condiție cond. Nu se întâmplă nimic dacă niciun fir de execuție nu așteaptă pe cond.

pthread_cond_wait() deblochează atomic mutex (conform pthread_mutex_unlock()) și așteaptă ca variabila de condiție cond să fie semnalată. Execuția firului este suspendată și nu consumă timp CPU până când variabila de condiție nu este semnalată. mutex trebuie să fie blocată de firul apelant la intrarea în pthread_cond_wait(). Înainte de a reveni la firul apelant, pthread_cond_wait() recuperează mutex (conform pthread_mutex_lock()).

Deblocarea mutex-ului și suspendarea pe variabila de condiție se face atomic. Astfel, dacă toate firele achiziționează întotdeauna mutex-ul înainte de a semnaliza condiția, acest lucru garantează că condiția nu poate fi semnalată (și, prin urmare, ignorată) între momentul în care un fir blochează mutex-ul și momentul în care așteaptă pe variabila de condiție. A se vedea secțiunea «AVERTISMENTE» de mai jos.

pthread_cond_timedwait() deblochează atomic mutex și așteaptă pe cond, la fel ca pthread_cond_wait, dar limitează și durata așteptării. Dacă cond nu a fost semnalată în intervalul de timp specificat de abstime, mutex-ul mutex este reacceptat din nou, iar pthread_cond_timedwait() returnează eroarea ETIMEDOUT. Parametrul abstime specifică un timp absolut, cu aceeași origine ca și time(2) și gettimeofday(2): un abstime de 0 corespunde la 00:00:00 GMT, 1 ianuarie 1970.

pthread_cond_destroy() distruge o variabilă de condiție, eliberând resursele pe care le-ar putea conține. La intrarea în pthread_cond_destroy() nu trebuie să existe fire de execuție care să aștepte variabila de condiție. În implementarea „LinuxThreads”, nu există resurse asociate variabilelor de condiție, astfel încât pthread_cond_destroy() nu face de fapt nimic, cu excepția verificării faptului că nu există fire de execuție în așteptare.

ANULARE
pthread_cond_wait() și pthread_cond_timedwait() sunt puncte de anulare. Dacă un fir este anulat în timp ce este suspendat într-una din aceste funcții, firul își reia imediat execuția, apoi blochează din nou argumentul mutex la pthread_cond_wait() și pthread_cond_timedwait() și, în final, execută anularea. În consecință, gestionarii de curățare sunt asigurați că mutex este blocat atunci când sunt apelați.

SIGURANȚA SEMNALELOR ASINCRONE
Funcțiile de condiție nu sunt sigure pentru semnale asincrone și nu ar trebui să fie apelate de la un gestionar de semnal. În special, apelarea pthread_cond_signal() sau pthread_cond_broadcast() de la un gestionar de semnal poate bloca firul apelant.

VALOAREA RETURNATĂ
Toate funcțiile de variabilă de condiție returnează 0 în caz de succes și un cod de eroare diferit de zero în caz de eroare.

ERORI-IEȘIRE
pthread_cond_init(), pthread_cond_signal(), pthread_cond_broadcast() și pthread_cond_wait() nu returnează niciodată un cod de eroare.

Funcția pthread_cond_timedwait() returnează următoarele coduri de eroare în caz de eroare:

    ETIMEDOUT
        Variabila de condiție nu a fost semnalată până la expirarea timpului de așteptare specificat de abstime.

Funcția pthread_cond_destroy returnează următorul cod de eroare în caz de eroare:

    EBUSY
        Unele fire sunt în prezent în așteptare pe cond.

CONSULTAȚI ȘI
pthread_condattr_init(3), pthread_mutex_lock(3), pthread_mutex_unlock(3), gettimeofday(2), nanosleep(2).

AVERTISMENTE
Implementarea funcțiilor furnizate până la glibc 2.25 utiliza un blocaj intern de date. Acest blocaj nu accepta moștenirea priorității și era supus unei inversări nelimitate a priorității, vizibilă într-un sistem în timp real.

După rescrierea implementării în glibc 2.25, utilizarea blocării interne s-a modificat. Blocarea internă este întotdeauna obținută de funcțiile de semnalizare pthread_cond_signal() și pthread_cond_broadcast(). Funcția de așteptare obține blocarea dacă procesul de așteptare a fost întrerupt. Întreruperea poate fi cauzată, de exemplu, de un timp de expirare specificat și indicată de valoarea de eroare ETIMEDOUTA sau de un semnal primit, care este indicat de valoarea de eroare EINTR.

EXEMPLU
Se consideră două variabile partajate x și y, protejate de mutex-ul mut, și o variabilă de condiție cond care trebuie semnalată ori de câte ori x devine mai mare decât y.

    int x,y; pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

Așteptarea până când x este mai mare decât y se efectuează după cum urmează:

    pthread_mutex_lock(&mut); while (x <= y) {         pthread_cond_wait(&cond, &mut); } /* operează asupra lui x și y */ pthread_mutex_unlock(&mut);

Modificările lui x și y care pot face ca x să devină mai mare decât y trebuie să semnalizeze condiția, dacă este necesar:

    pthread_mutex_lock(&mut); /* modificarea lui x și y */ if (x > y) pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mut);

Dacă se poate dovedi că cel mult un singur fir în așteptare trebuie să fie trezit (de exemplu, dacă există doar două fire care comunică prin x și y), pthread_cond_signal() poate fi utilizat ca o alternativă puțin mai eficientă la pthread_cond_broadcast(). În caz de îndoială, utilizați pthread_cond_broadcast().

Pentru a aștepta ca x să devină mai mare decât y cu un timp de așteptare de 5 secunde, faceți:

    struct timeval now; struct timespec timeout; int retcode;  pthread_mutex_lock(&mut); gettimeofday(&now); timeout.tv_sec = now.tv_sec + 5; timeout.tv_nsec = now.tv_usec * 1000; retcode = 0; while (x <= y && retcode != ETIMEDOUT) {         retcode = pthread_cond_timedwait(&cond, &mut, &timeout); } if (retcode == ETIMEDOUT) {         /* a avut loc terminarea timpului de așteptare */ } else {         /* operează asupra lui x și y */ } pthread_mutex_unlock(&mut);

TRADUCERE
Traducerea în limba română a acestui manual a fost făcută de Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>

Această traducere este documentație gratuită; citiți Licența publică generală GNU Versiunea 3 (https://www.gnu.org/licenses/gpl-3.0.html) sau o versiune ulterioară cu privire la condiții privind drepturile de autor. NU se asumă NICIO RESPONSABILITATE.

Dacă găsiți erori în traducerea acestui manual, vă rugăm să trimiteți un e-mail la translation-team-ro@lists.sourceforge.net.