Semafoare (continuare)
Laboratorul trecut, am văzut cum semaforul reprezintă o generalizare a unui mutex. Un semafor iniţializat cu 1 poate fi folosit drept lock, pentru că doar un thread are acces la zona critică la un moment de timp. Totuși, un semafor poate avea întrebuinţări mult mai complexe, deoarece poate lua diverse valori, atât negative, cât şi pozitive.
Când un semafor este iniţializat cu valoarea pozitivă x, vă puteţi gândi că x thread-uri au voie să intre în secţiunea critică. Pe măsură ce un thread face acquire(), x este decrementat. Când se ajunge la 0, alte posibile thread-uri care vor să acceseze regiunea critică vor trebui să aştepte până când valoarea semaforului creşte la o valoare pozitivă (adică până când iese câte un thread din cele aflate în regiunea critică).
Complementar, când un semafor este iniţializat cu o valoare negativă cum ar fi -1, se aşteaptă ca cel puţin două thread-uri să facă întâi release() (pentru ca valoarea semaforului să crească de la -1 la 1), înainte ca o regiune critică să poată fi accesată (adică un alt thread să poată face acquire()). Vă puteţi imagina că un al treilea thread aşteaptă "la semafor" ca alte două thread-uri să îi dea un semnal prin apelul release() când şi-au "terminat treaba". Puteți observa un exemplu în pseudocodul de mai jos.
Semaphore sem = new Semaphore(-1); | ||
T0 | T1 | T2 |
---|---|---|
// aşteaptă la semafor // după celelalte 2 thread-uri sem.acquire(); // sem = 1, deci poate trece System.out.println("Am trecut de semafor!"); | do_work1(); sem.release(); // sem = -1 + 1 = 0 | do_work2(); sem.release(); // sem = 0 + 1 = 1 |