MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Monitoare

Pe lângă operatorul lock pentru sincronizarea thread-urilor, putem folosi monitoarele, reprezentate de clasa System.Threading.Monitor. Pentru gestionarea sincronizării, această clasă oferă următoarele metode:

  • void Enter(object obj): obține în posesie exclusivă obiectul transmis ca parametru
  • void Enter(object obj, bool acquiredLock): în plus, primește un al doilea parametru - o valoare booleană care indică dacă posesia asupra obiectului din primul parametru a fost obținută
  • void Exit(object obj): eliberează obiectul capturat anterior
  • bool IsEntered(object obj): returnează true dacă monitorul a capturat obiectul obj
  • void Pulse(object obj): notifică thread-ul din coada de așteptare că thread-ul curent a eliberat obiectul obj
  • void PulseAll(object obj): notifică toate thread-urile din coada de așteptare că thread-ul curent a eliberat obiectul obj. După aceasta, unul dintre thread-urile din coada de așteptare capturează obiectul obj
  • bool TryEnter(object obj): încearcă să captureze obiectul obj. Dacă posesia asupra obiectului este obținută cu succes, returnează valoarea true
  • bool Wait(object obj): eliberează blocarea obiectului și pune thread-ul în coada de așteptare a obiectului. Următorul thread din coada de așteptare capturează acest obiect. Toate thread-urile care au apelat metoda Wait rămân în coada de așteptare până când primesc un semnal de la metoda Monitor.Pulse sau Monitor.PulseAll, transmis de deținătorul blocării

Merită menționat că, în fapt, construcția operatorului lock încapsulează sintaxa de utilizare a monitoarelor. De exemplu, în tema anterioară, pentru sincronizarea thread-urilor a fost folosit operatorul lock:

int x = 0;
object locker = new();  // obiect placeholder

// pornim cinci thread-uri
for (int i = 1; i < 6; i++)
{
   Thread myThread = new(Print);
   myThread.Name = $"Thread {i}";
   myThread.Start();
}

void Print()
{
   lock (locker)
   {
       x = 1;
       for (int i = 1; i < 6; i++)
       {
           Console.WriteLine($"{Thread.CurrentThread.Name}: {x}");
           x++;
           Thread.Sleep(100);
       }
   }
}

De fapt, acest exemplu este echivalent cu următorul cod:

int x = 0;
object locker = new();  // obiect placeholder

// pornim cinci thread-uri
for (int i = 1; i < 6; i++)
{
   Thread myThread = new(Print);
   myThread.Name = $"Thread {i}";
   myThread.Start();
}

void Print()
{
   bool acquiredLock = false;
   try
   {
       Monitor.Enter(locker, ref acquiredLock);
       x = 1;
       for (int i = 1; i < 6; i++)
       {
           Console.WriteLine($"{Thread.CurrentThread.Name}: {x}");
           x++;
           Thread.Sleep(100);
       }
   }
   finally
   {
       if (acquiredLock) Monitor.Exit(locker);
   }
}

Metoda Monitor.Enter acceptă doi parametri: obiectul de blocare și o valoare booleană care indică rezultatul blocării (dacă este true, blocarea a fost realizată cu succes). De fapt, această metodă blochează obiectul locker la fel cum face operatorul lock. Iar în blocul try...finally, cu ajutorul metodei Monitor.Exit, obiectul locker este eliberat dacă blocarea a fost realizată cu succes, și devine disponibil pentru alte thread-uri.

← Lecția anterioară Lecția următoare →