Monitor (sincronizare)

De la Wikipedia, enciclopedia liberă.
Salt la navigare Salt la căutare

Un monitor , în programare, este o construcție de sincronizare a unui limbaj la nivel înalt. O instanță de tip monitor poate fi utilizată de două sau mai multe procese sau fire pentru a face accesul la resursele partajate care se exclud reciproc. Avantajul utilizării monitorului provine din faptul că niciun mecanism nu trebuie codificat în mod explicit pentru a realiza excluderea reciprocă, deoarece monitorul permite ca un singur proces să fie activ în cadrul acestuia.

Caracteristici

Un monitor tipic constă din:

  • variabile locale, ale căror valori definesc starea unei instanțe de tipul monitorului;
  • un bloc de inițializare sau o procedură pentru inițializarea valorilor de date locale ale unei instanțe de tip (numită și constructor).
  • un set de corpuri de proceduri sau funcții care efectuează operațiuni de acest tip.

Variabilele locale sunt declarate private, ceea ce înseamnă că sunt accesibile doar prin proceduri de monitorizare. Atunci când un monitor este instanțiat, blocul de inițializare este pornit sau procedura de inițializare a acestuia trebuie invocată, similar modului în care este invocată o metodă constructor a unei clase de limbaj de programare orientată obiect atunci când este instanțiat.un obiect, sau, într-adevăr, dacă monitor este o clasă de obiect. Un proces intră într-un monitor invocând una dintre procedurile sale. Un singur proces poate fi activ în cadrul monitorului la un moment dat, astfel încât atunci când un proces invocă o procedură, cererea este pusă în coadă și satisfăcută de îndată ce monitorul este liber.

Structura generică a unui monitor:

 monitor monitor_name {

      / * spațiu pentru declararea variabilelor partajate * /

      procedure procedure_name_1 (parametru_1, ..., parametru_N) {
         / * codul corpului procedurii * /
      }
       . . .
      procedure procedure_name_N (parametru_1, ..., parametru_N) {
         / * codul corpului procedurii * /
      }

      {
         / * codul blocului de inițializare * /
      }
   }

Un exemplu de monitor:

 monitor current_account {
  echilibru dublu : = 0,0
  
  retragerea procedurii (suma dublă ) {
    dacă suma <0,0 atunci eroarea "Valoarea retragerii trebuie să fie un număr pozitiv"
    altfel, dacă soldul <suma, atunci eroarea „Fonduri insuficiente pentru retragere”
    else balance: = sold - suma
  }
  
  procedura versa (suma dublă ) {
    dacă suma <0,0 atunci eroarea "Valoarea depozitului trebuie să fie un număr pozitiv"
    else sold: = sold + suma
  }
 
  echilibru funcție dublă () {
    soldul de retur
  }
}

În exemplu, aveți garanția că tranzacția actualizează corect soldul contului curent.

Variabile condiționale

Fără alte mecanisme, constrângerea strictă de excludere reciprocă a constructului nu ar permite sincronizări particulare. În schimb, variabilele condiționale, de condiție de tip, care pot fi definite printre alte variabile locale, și procedurile de așteptare (condiția x) și notificare (condiția x), singurele care pot fi invocate pe acestea, oferă unui programator instrumentele necesar pentru a vă scrie propria schemă de sincronizare. Operațiunea wait (), aplicată unei variabile condiționale, vă permite să suspendați un proces care ocupă monitorul, determinând procesul să dispară temporar de pe monitor și să fie plasat într-o coadă de așteptare pentru acea variabilă condițională, oferind astfel gratuit unui nou proces care dorește să intre în monitor sau la un alt proces gata, la o variabilă condițională, pentru a relua execuția. Operația de notificare () trezește exact un proces suspendat pe variabila condițională pentru care este apelată; acest proces își reia executarea imediat ce are undă verde. În orice caz, atunci când nu există procese care așteaptă variabila condițională pentru care este apelată notificarea, nu se întâmplă nimic. Notificarea, pe baza politicilor sale de trimitere, poate da naștere la diferite evoluții ale sistemului, rezumate aici:

  • notificare urgentă (semnal urgent): reactivarea imediată a unui proces de așteptare a variabilei pentru care se apelează notificarea are loc, în timp ce procesul care efectuează notificarea este pus în coada de așteptare a aceluiași, pentru a fi reactivat la trezire procesul părăsește monitorul sau pune în așteptare o variabilă condițională; soluție susținută de CAR Hoare ;
  • notificare și returnare (semnal și returnare): procesul, după finalizarea notificării, iese imediat de pe monitor;
  • notificați și continuați (semnalizați și continuați): procesul, după finalizarea notificării, continuă executarea acestuia; numai după ce a părăsit monitorul sau a fost pus în așteptare pe o variabilă condițională, procesul din capul cozii de așteptare a variabilei condiționale pentru care a fost făcută notificarea este reactivat.

Următorul este un exemplu de monitor care utilizează variabile condiționale pentru a implementa un canal de comunicație interproces (de exemplu, o conductă ), care poate stoca doar un număr întreg la un moment dat.

 monitor de canal {
  container int
  boolean umplut: = false
  stare livrată
  starea primită

  funcție trimitere (valoare int ) {
    dacă este plin de așteptare , apoi (primit)
    container: = valoare
    plin: = adevărat
    notificare (trimisă)
  }

  funcția int receive () {
    în cazul în care nu este plin apoi așteptați (expediate)    
    plin: = false
    notificare (primită)
    returnează containerul
  }
}

Să încercăm să simulăm o posibilă execuție a monitorului de canal luată ca exemplu. Să presupunem că un prim proces cere monitorului să primească și se oprește deoarece canalul nu este plin; în acest moment, dispare de pe monitor, în așteptarea apariției stării „expediate”. Să presupunem, în plus, că alte trei procese cer să primească: toate sunt la coadă între procesele care trebuie trezite pe variabila condițională trimisă . Atâta timp cât nu există procese care trimit un număr întreg pe canal, prin invocarea send (), cele patru procese ale noastre sunt în așteptare pentru o expediere. Numai în cazul în care, în cele din urmă, ajunge un proces care necesită monitorul să trimită, de exemplu cu send (3) , deoarece nu există alte procese care să utilizeze monitorul (cele patru procese aflate în coada variabilei condiționale „trimise” sunt toate invizibil), monitorul observă că containerul este gol, îl umple și anunță că canalul a trimis date. Această notificare, în funcție de politica utilizată, afectează procesul din capul cozii de așteptare a variabilei condiționale trimise .

Istorie

Propus inițial de Per Brinch Hansen pe baza lucrărilor anterioare ale CAR Hoare . Hoare însuși a dezvoltat ulterior teoria monitoarelor și a dovedit că, din punct de vedere al puterii expresive, monitoarele erau echivalente cu semafoarele .

Monitoarele au fost inițial propuse ca model teoretic, dar au fost adoptate ulterior de multe limbaje de programare concurente . Citeva exemple de limbi care permit utilizarea monitoarelor pot fi citate:

Limbajul C # nu are monitoare ca o caracteristică primitivă a limbajului, dar o funcție similară este asigurată de o clasă de bibliotecă a cadrului .NET .

Monitoarele au fost adoptate de mai multe sisteme de operare ca un mecanism de control al concurenței (deși mecanismele primitive se bazează în general pe conceptul de semafor): un exemplu este interfața POSIX pthreads .

Bibliografie

  • Monitoare: un concept de structurare a sistemului de operare, CAR Hoare - Communications of the ACM, v.17 n.10, p. 549-557, octombrie 1974 [1]
  • Clasificarea monitorului PA Buhr, M. Fortier, MH Coffin - ACM Computing Surveys (CSUR), 1995 [2]

Alte proiecte

Informatică Portal IT : accesați intrările Wikipedia care se ocupă cu IT