Politicile generice de sincronizare în C + +
Acest software și documentație sunt distribuite sub o licență MIT-stil (de mai jos), care, practic, înseamnă că nu trebuie să scoateți copyright, dar, în afară de faptul că, puteți utiliza sau modifica acest software și documentație, după cum doriți. De exemplu, îl puteți folosi în ambele proiecte open-source și închis-sursă, și vă pot da departe software-ul și documentația gratis sau puteți să-l vinzi. Puteți găsi informații despre open-source de licențe de la Open Source Initiative (www.opensource.org).
Copyright © 2006-2008 Ciaran McHale.
Permisiunea se acordă, gratuit, oricărei persoane care obține o copie a acestui software și a fișierelor de documentație asociate ( "Software-ul"), să folosească software-ul fără restricție, inclusiv, fără limitare a drepturilor de a utiliza, copia, modifica, îmbinare , publica, distribui, sublicenția, și / sau vinde copii ale software-ului, și să permită persoanelor cărora Software-ul este furnizat să facă acest lucru, sub rezerva următoarelor condiții:
Drepturi de autor de mai sus și acest aviz de permisiune trebuie să fie incluse în toate copiile sau porțiuni substanțiale ale software-ului.
SOFTWARE ESTE OFERIT "CA ATARE", FĂRĂ NICIUN FEL DE GARANȚIE, EXPLICITĂ SAU IMPLICITĂ, INCLUSIV, DAR FĂRĂ A SE LIMITA LA GARANȚII DE COMERCIALIZARE, POTRIVIRE PENTRU UN ANUMIT SCOP ȘI NEÎNCĂLCARE. ÎN NICI UN CAZ AUTORII SAU DEȚINĂTORII DREPTURILOR DE AUTOR NU VOR FI RESPONSABILI PENTRU ORICE REVENDICARE, DAUNE SAU ALTE RĂSPUNDERI, FIE ÎN DERULAREA UNUI CONTRACT SAU ALTFEL, REZULTA DIN, DIN SAU ÎN LEGĂTURĂ CU SOFTWARE-UL SAU UTILIZAREA SAU CU ALTE SOFTWARE.
1 Introducere
Scrierea de cod de sincronizare este, de obicei atât de dificil și non-portabil.
O mare parte din dificultatea de a scrie cod de sincronizare se datorează utilizării de API-uri de sincronizare de nivel scăzut.
Problema apare deoarece nici portabilitate C, nici C + + oferă o bibliotecă standard pentru sincronizare. Ca rezultat, multe sisteme de operare oferă API-uri de proprietate, pentru sincronizare. Unii oameni scriu o bibliotecă de portabilitate în strat care ascunde API-urile de proprietate ale sistemelor de operare care stau la baza. Din păcate, aceasta este comun pentru astfel de biblioteci pentru a oferi un nivel scăzut, și, prin urmare dificil de utilizat, API.
În experiența mea, cele mai multe utilizări ale codului de sincronizare în aplicații multi-threaded se încadrează într-un număr mic de înalt nivel "modelele de utilizare", sau ceea ce eu numesc politici generice de sincronizare (SGP). Această lucrare ilustrează modul de utilizare a SGP astfel simplifica scrierea de thread-safe clase. În plus, această lucrare prezintă un C + + biblioteca clasa care implementeaza SGP frecvent utilizate.
2 Broaste scoped
Bibliotecile filetare oferă funcții care achiziționează și se eliberează de excludere reciprocă (mutex) încuietori. În această lucrare, am folosi getLock () și releaseLock () pentru a indica astfel de funcții. O secțiune critică este un cod care este fixata apeluri la getLock () și releaseLock (). De exemplu, următorul este o secțiune critică:
getLock(mutex); ... releaseLock(mutex); Secțiunea de mai sus critică pare simplu. Cu toate acestea, în cazul în care codul într-o secțiune critică declarațiile are condiționale de returnare sau aruncă excepții, atunci condiționat de îngrijire trebuie să fie luate pentru a elibera blocarea mutex-ul de la toate punctele de ieșire din secțiunea critică. Figura 1 prezintă un exemplu în acest sens. void foo() { getLock(mutex); ... if (...) { releaseLock(mutex); return; } if (...) { releaseLock(mutex); throw anException; } ... releaseLock(mutex); }Figura 1: O operație cu o secțiune critică În general, adăugarea de apeluri la releaseLock () la fiecare punct de ieșire potențialul de a Clutter sectiunii critice de până cod, făcând astfel codul de mai dificil de citit și să mențină. Într-adevăr, o sursă comună de bug-uri în aplicații multi-threaded este că uităm să adăugați un apel de releaseLock () la unele dintre punctele de ieșire posibile ale unei secțiuni critice. Există o tehnică utilă, care elimină necesitatea pentru aglomera, predispusă la erori apelurile către releaseLock (). Aceasta tehnica presupune o clasă a scris-sa spunem ScopedMutex-care solicită getLock () și releaseLock () în constructorul și destructor. Puteți vedea o punere în aplicare pseudocod a acestei clase în figura 2. class ScopedMutex { public: ScopedMutex(Mutex & mutex) : m_mutex(mutex) { getLock(m_mutex); } ~ScopedMutex() { releaseLock(m_mutex); } protected: Mutex & m_mutex; };Figura 2: Un pseudocod ScopedMutex clasa Acum, in loc sa apeleze în mod explicit getLock () și releaseLock () în organism a unei operații, puteți doar să declarați o variabilă ScopedMutex local pentru functia. Figura 3 prezintă un exemplu în acest sens. Când funcția este numit, constructorul a variabilei ScopedMutex este invocată și aceasta getLock apeluri (). Apoi, atunci când funcția se termină, destructor al variabilei ScopedMutex este invocată și aceasta releaseLock apeluri (). Acest lucru se întâmplă indiferent dacă funcția returnează timpurie (linia 1), aruncă o excepție (linia 2) sau execută până la finalizare (linia 3). void foo() { ScopedMutex scopedLock(mutex); ... if (...) return; // line 1 if (...) throw anException; // line 2 ... } // line 3Figura 3: O operație cu un sistem de blocare scoped mutex Dacă veți compara codul în figurile 1 și 3, atunci vei vedea ca codul acesta din urmă (care folosește clasa ScopedMutex) este mai scurt și mai ușor de citit decât fostul. Aceasta tehnica de a folosi un constructor / destructor pentru clasa de sincronizare este parțial bine-cunoscute în C + + comunității. Spun acest lucru din două motive. În primul rând, experiența mea ca un consultant si trainer mi-a dat oportunitatea de a lucra cu mai multe programatori C + + în organizarea multe diferite. Am constatat că aproximativ jumătate din programatori cu care lucrez sunt familiarizați cu această tehnică și pentru a vizualiza aceasta ca fiind o bază C + + expresie, în timp ce aceeasi tehnica este nou pentru cealaltă jumătate. În al doilea rând, printre programatori care au folosit acest constructor / destructor tehnica pentru sincronizare, utilizarea acestei tehnici invariabil se limitează la excludere reciprocă (și, ocazional, cititorii-scriitor încuietori). Cu toate acestea, aceasta tehnica este aplicabilă alt cod, sincronizarea mult mai complexă prea (care este punctul central al acestei lucrări). Înainte de a discuta modul în care să aplice această tehnică pentru a cod de sincronizare parte, este necesar să se ia un ocol ușoară. În special, trebuie să se introducă un nou concept: acela al politicilor de sincronizare generice. 3 Politici generice de sincronizare C + + acceptă tipuri de șabloane. De exemplu, o clasa de listă ar putea fi scrisă sub forma: template<T> class List { ... }; Odată pus în aplicare, acest tip de șablon poate fi instanțiat de mai multe ori pentru a obține, de exemplu, o listă de int, o listă de dublu și o listă de widget: List<int> myIntList; List<double> myDoubleList; List<Widget> myWidgetList;Capacitatea de a defini tipurile de șablon nu este unic pentru C + +. Multe alte limbi oferi functionalitate similara, desi adesea există diferențe de terminologie și sintaxa. De exemplu, unele tipuri de limbi folosesc termenul generic, mai degrabă decât tipuri de șablon, iar parametrii de tip ar putea fi închisă în termen de [si] in loc de <si>. Conceptul de genericitatea nu este limitată la tipuri. Acesta poate fi aplicat la sincronizarea prea, cum am discuta acum. 3.1 mutex și-Cititorii scriitor Politici Folosind o notație pseudocod, pot să declar unor politici bine-cunoscute de sincronizare, după cum urmează: Mutex[Op] RW[ReadOp, WriteOp]În această notație, numele politicii de sincronizare generic este dat în primul rând, și apoi este urmată de o listă de parametri între paranteze drepte. Fiecare parametru denotă un set de nume de operare. De exemplu, politica de mutex este instantiat la un set de operațiuni (OP), în timp ce RW (cititori-scriitor), politica este instanțiat la un set de citire-stil operațiuni (ReadOp) și un set de scriere stil operațiuni (WriteOp) . Luați în considerare o clasă care are două-în-citire în stil operațiuni numite OP1 și OP2, precum și o operație de scriere în stil numit OP3. Am instantia politica RW asupra acestor operațiuni, după cum urmează: RW [{OP1, OP2}, {} OP3] De asemenea, o instanțiere a politicii mutex asupra acestor trei operațiuni este scris, după cum urmează: Mutex-ul [{OP1, OP2, OP3}] 3.2 Politica de producător-consumator Politica de producător-consumator este utilă atunci când un tampon este utilizat pentru a transfera date de la un fir de executie (producător), într-un alt fir (de consum).Firul Producătorul pune elemente în tampon și apoi, cândva mai târziu, firul consumatorul primește aceste elemente. Dacă firul consumatorul încearcă să obțineți un element dintr-un tampon gol, atunci aceasta va fi blocat până tampon nu este gol. În plus, operațiunile de put-stil și de a lua în stil executa la excluderea reciprocă; acest lucru este pentru a preveni tampon de a deveni corupt din cauza accesului concurent. Această politică este scris, după cum urmează: ProdCons[PutOp, GetOp, OtherOp]OtherOp denotă orice alte operațiuni (non-a pus în stil și non get-stil), pe clasa de tampon. De exemplu, poate exista o operație pe tampon care returnează un număr de cât de multe elemente sunt în prezent în tampon. O astfel de operațiune ar putea avea nevoie pentru a rula în excludere reciprocă cu put stil și de a lua în stil operațiuni pentru a asigura funcționarea corectă a acestuia. În cazul în care o clasă-tampon stil are operatiuni numite inserați (), remove () si numara () le puteti instantia politica PRODCONS pe clasa, după cum urmează: ProdCons[{insert}, {remove}, {count}]În cazul în care clasa nu are o operațiune de count () le puteti instantia politica PRODCONS pe ea, după cum urmează: ProdCons[{insert}, {remove}, {}]În acest caz, parametrul OtherOp a politicii este instantiat la un set gol de nume operațiuni. 3.3 delimitate producător-consumator Politica O variantă comună a politicii de producător-consumator este mărginită producător-consumator politică, în care buffer are o dimensiune fixă. Acest lucru previne tampon de creștere infinit de mare în cazul în care un fir de executie pune elemente în tampon mai repede decat alt fir se poate lua pe ei. În această politică, în cazul în firul de producători încearcă să pună un element într-un tampon deja plin, atunci acesta va fi blocat până tampon nu este plin. Această politică este scris, după cum urmează: BoundedProdCons(int size)[PutOp, GetOp, OtherOp]Observați că dimensiunea buffer-ului este specificat ca un parametru la numele politicii. Astfel de parametri sunt, de obicei, instanțiat la un parametru care corespunde constructorul buffer; un exemplu în acest sens va fi indicat ulterior (în figura 7). 4 Politici de sincronizare generice în C + + Discuție în secțiunea 3 axat pe conceptul de SPG. Am explica acum cum să pună în aplicare SPG în C + +. Figura 4 prezinta cartografiere a mutex [Op] Politica intr-o clasa C + + folosind firele POSIX. Rețineți că, pentru a păstra concis codul, controalele de eroare pe valorile de returnare ale firele POSIX apelurile de bibliotecă au fost omise. 1 class GSP_Mutex { 2 public: 3 GSP_Mutex() { pthread_mutex_init(m_mutex, 0); } 4 ~GSP_Mutex() { pthread_mutex_destroy(&m_mutex); } 5 6 class Op { 7 public: 8 Op(GSP_Mutex &) : m_data(data) 9 { pthread_mutex_lock(&m_data.m_mutex); } 10 ~Op() { pthread_mutex_unlock(&m_data.m_mutex); } 11 protected: 12 GSP_Mutex & m_data; 13 }; 14 15 protected: 17 pthread_mutex_t m_mutex; 16 friend class ::GSP_Mutex::Op; 18 };Figura 4: Cartografierea mutex [Op] într-o clasă C + + Cartografiere de la un SPG într-o clasă C + + se face după cum urmează: Numele de C + + clasa este aceeași ca și numele GSP, dar cu un "GSP_" prefixul.Prefix este folosit pentru a preveni poluarea spațiu de nume. Deci, în Figura 4 GSP mutex este pusă în aplicare de către clasa GSP_Mutex. Clasa are una sau mai multe variabile de instanta (linia 17) care oferă depozitare pentru mutex-ul.Constructorul si destructorul clasei (liniile 3 și 4) inițializa și de a distruge variabila instanta (e). Mutex [Op] GSP are un parametru numit Op. Acest lucru se traduce într-o clasă imbricată (liniile 6-13) cu același nume. Dacă un GSP are mai mulți parametri, apoi fiecare parametru traduce într-o clasă imbricată separat; un exemplu în acest sens va fi indicat ulterior. Fiecare clasă imbricată are o variabilă instanță (linia 12), care este o referire la clasa de exterior. Această variabilă instanță este initializat de la un parametru la constructorul clasei interior (linia 8). Constructorul si destructorul clasei imbricate obține și a elibera blocare (liniile 9 și 10) stocate în instanță a clasei exterioare. Ca un alt exemplu, Figura 5 arată cum RW [ReadOp, WriteOp] GSP hărți într-o clasă C + +. Observați că, deoarece această GSP are doi parametri, există două clase imbricate. class GSP_RW { public: GSP_RW() { /* initialize the readers-writer lock */ } ~GSP_RW() { /* destroy the readers-writer lock */ } class ReadOp { public: ReadOp(GSP_RW & data) : m_data(data) { /* acquire read lock */ } ~ReadOp() { /* release read lock */ } protected: GSP_RW & m_data; }; class WriteOp { public: WriteOp(GSP_RW & data) : m_data(data) { /* acquire write lock */ } ~WriteOp() { /* release write lock */ } protected: GSP_RW & m_data; }; protected: ... // Instance variables required to implement a // readers-writer lock friend class ::GSP_RW::ReadOp; friend class ::GSP_RW::WriteOp; };Figura 5: Clasa GSP_RW cu ReadOp imbricate și clasele WriteOp Instantierea unui SPG asupra operațiunilor de o clasa C + + implică următoarele trei etape: # include fișierul antet pentru GSP.Numele fișierului antet este același ca și numele clasei SPG, dar scrise cu litere mici. De exemplu, fișierul antet pentru clasa GSP_RW este "gsp_rw.h". Adăugați o variabilă instanță pentru C + + clasa care urmează să fie sincronizate. Tipul de variabilă instanță este faptul că de clasa exterior GSP lui. În interiorul corpului fiecărei operațiuni care urmează să fie sincronizate, a declara o variabilă locale, tipul de care este acela al unei clase imbricate de GSP. Instanțierea RW [{OP1, OP2}, {} OP3] în Figura 6 ilustrează pașii de mai jos. #include "gsp_rw.h" class Foo { public: Foo() { ... } ~Foo() { ... } void Op1(...) { GSP_RW::ReadOp scopedLock(m_sync); ... // normal body of operation } void Op2(...) { GSP_RW::ReadOp scopedLock(m_sync); ... // normal body of operation } void Op3(...) { GSP_RW::WriteOp scopedLock(m_sync); ... // normal body of operation } protected: GSP_RW m_sync; ... // normal instance variables of class };Figura 6: instanțierea GSP_RW Ca un ultim exemplu, Figura 7 arată o clasă care este instantiat cu: BoundedProdCons(int size)[PutOp, GetOp, OtherOp]Această politică are un parametru care indică dimensiunea buffer. Acest parametru este obținut din parametrul bufSize a constructorului clasei. #include "gsp_boundedprodcons.h" class WidgetBuffer { public: WidgetBuffer(int bufSize) : m_sync(bufSize) { ... } ~WidgetBuffer() { ... } void insert(Widget * item) { GSP_BoundedProdCons::PutOp scoped_lock(m_sync); ... // normal body of operation } Widget * remove() { GSP_BoundedProdCons::GetOp scoped_lock(m_sync); ... // normal body of operation } protected: GSP_BoundedProdCons m_sync; ... // normal instance variables of class };Figura 7: instanțierea GSP_BoundedProdCons 5 Suport pentru Politici de sincronizare generice în alte limbi Punerea în aplicare a SGP prezentat în această lucrare se bazează pe constructori si destructori pentru a automatiza executarea de cod de sincronizare. Deși orientate obiect limbile oferă, de obicei, constructori, nu toate limbile orientate-obiect oferi destructori, în special de limbi care au construit-in colectoare de gunoi. Acest lucru poate duce la concluzia că cititorii SGP nu pot fi puse în aplicare în limbile existente, care nu oferă destructori. În timp ce acest lucru poate fi așa, ar fi posibil pentru designeri de limbi viitoare să includă sprijin pentru SGP în proiectarea limba lor. De exemplu, în Ph.D. mea Teza [] am arăta cum să adăugați suport pentru SGP la compilator de un limbaj orientat-obiect, care foloseste in loc de colectare a gunoiului de destructori. 6 O critică a politicilor de sincronizare generice Am puncta acum câteva avantaje și dezavantaje potențiale ale SGP. 6.1 Punctele forte ale SGP În primul rând, SGP oferă o formă bună de reutilizare aptitudini. În special, aceasta este mult mai ușor de a utiliza o SPG decât este de a pune în aplicare unul. Astfel, un programator calificat în programare sincronizare poate pune în aplicare orice SGP sunt necesare pentru un proiect, și apoi altele, mai puțin calificați, programatorii pot utiliza aceste SGP pre-scris. În al doilea rând, SGP codul lizibilitatea ajutor și întreținere prin separarea cod de sincronizare de la "normal", cod funcțională a unei clase. În al treilea rând, așa cum am discutat în Secțiunea 2, introducerea codului de sincronizare în constructor si destructor a claselor SPG înseamnă că încuietorile sunt puse, chiar dacă o operațiune se încheie prin întoarcerea mai devreme sau aruncarea o excepție. Acest lucru elimina o sursă comună de bug-uri în programele multi-threaded. În al patrulea rând, SGP oferă nu numai ușurința de utilizare, ele oferă, de asemenea, un strat de portabilitate în jurul valorii de primitivele de sincronizare subiacente. Desigur, unele companii au dezvoltat in-house, biblioteci portabilitatea, care se ascund diferențele dintre primitivele de sincronizare pe diverse platforme, și alte companii să utilizeze bibliotecile portabilitate terțe părți, cum ar fi Threads.h + + biblioteca de la RogueWave.Utilizarea SGP este compatibil cu bibliotecile existente astfel: SGP pot fi puse în aplicare la fel de ușor pe partea de sus a Threads.h + + (sau unele bibliotecă portabilitatea altele), deoarece acestea pot fi puse în aplicare în mod direct pe partea de sus a sistemului de operare primitive de sincronizare specifice. În cele din urmă, punerea în aplicare a unui SPG poate fi inline. Astfel, utilizarea de SGP nu trebuie să impună o deasupra capului de performanță. 6.2 Critici potențiale ale SGP Unii cititori ar putea fi de gândire: "SGP sunt limitate, ei nu se pot ocupa de toate are nevoie de sincronizare ar putea să am." Cu toate acestea, în multe activități, o sumă disproporționat de mare de rezultate provin dintr-o cantitate relativ mică de investiții. Acest lucru este, în general, cunoscut sub numele de principiul 80/20 []. În experiența mea, acest lucru este valabil pentru cerințele de aplicații de sincronizare. Un mic set de SGP este probabil să fie suficient pentru cele mai multe dintre nevoile de sincronizare de programatori. Deci, chiar dacă un mic set de pre-scrise SGP nu poate ocupa de toate are nevoie de sincronizare, care se va confrunta cu un programator, principiul 80/20 sugerează că utilizarea SGP ar fi util suficient de des pentru a justifica utilizarea lor. Desigur, oamenii nu se limitează doar la un mic set de pre-scrise SGP. Oamenii pot defini SGP noi. De exemplu, poate un programator trebuie să scrie niște cod specifice proiectului de sincronizare. Chiar dacă acest cod de sincronizare va fi folosit într-un singur loc doar în proiect, este greu de orice eforturi suplimentare pentru a pune în aplicare acest lucru ca un SPG și apoi l instantia, mai degrabă decât să pună în aplicare o "in-line" în operațiunile de o clasă. Făcând nu ofera mai multe avantaje: Punerea în aplicare a codului de sincronizare ca GSP este de natură să amelioreze lizibilitatea și întreținere a codului de sincronizare și codul secvențială a proiectului. Dacă programatorul descoperă mai târziu, un alt loc care are nevoie pentru a utiliza aceeași politică, atunci SPG poate fi re-utilizat direct, mai degrabă decât a fi nevoie de a re-utilizat în mărginită de cod prin copiere-n-paste. Unii cititori ar putea fi de gândire alte: "SGP nu sunt noi;" SGP "este doar un nume nou pentru un existent de programare C + + expresie". Afirmația că SGP se bazează pe un deja-cunoscuta expresie C + + (clasa ScopedMutex discutat în secțiunea 2) este în întregime adevărat. Într-adevăr, clasa ScopedMutex este un SPG în toate numele, dar. Cu toate acestea, după cum sa discutat în secțiunea 2, C + + expresie care sta la baza SGP a fost utilizată anterior doar pentru mutex-ul și, ocazional, politicile de cititori-scriitor. O contribuție semnificativă a SGP este in subliniind faptul că aceeași tehnică poate fi utilizată pentru cele mai multe, dacă nu toate, politicile de sincronizare. 7 Probleme care nu sunt abordate de către SPG SGP ilustra principiul 80/20: cele mai multe dintre cerințele de sincronizare de programatori pot fi îndeplinite de o mică colecție de SGP. Cu toate acestea, există unele probleme de sincronizare, care nu sunt abordate de SGP. Acum discuta pe scurt aceste probleme de mai jos, astfel încât cititorii să poată fi prevenit despre când utilizarea SGP nu este potrivit. 7.1 Subiect anulare Caietul de sarcini POSIX fire prevede un mecanism pentru un fir de executie sa fie anulate, adică, terminat cu grație. Atunci când un fir este anulat, este important ca firul are o sansa de a face unele curățenie înainte de a fi încheiată, de exemplu, firul se poate elibera dorința de a lacate pe care le deține. Acest lucru este realizat prin având în registrul de funcții programator de apel invers, care va fi invocate în cazul firului fiind anulate.Punerea în aplicare a SGP actual nu oferă sprijin pentru capacitatea de anulare firul de fire POSIX. Acest lucru nu se datorează nici o incompatibilitate între intrinsecă SGP și de anulare fir. Mai degrabă, este pur și simplu datorită autorului nu au nevoie să facă uz de anulare fir. SGP integrarea cu filet anulare este lăsată ca exercițiu pentru cititorii interesați. 7.2 Expirări Unele pachete fir oferă o capacitate de expirare a primitive de sincronizare. Prin folosirea acestui, un programator poate specifica o limită de timp superior cu privire la modul de mult un fir ar trebui să aștepte până la, să zicem, pentru a primi un sistem de blocare. Punerea în aplicare a SGP actual nu oferă o capacitate de timeout. Există două motive pentru acest lucru. În primul rând, timeout sunt rareori necesare și, prin urmare, urmând principiul 80/20, am decis să nu deranjeze sprijinirea acestora. În al doilea rând, punerea în aplicare a unei capacități de timeout este relativ complexă cu API-urile unor pachete fire. De exemplu, o politică mutex fără o capacitate de timeout poate fi pus în aplicare în mod trivial firele POSIX prin invocarea funcții pe un tip de suport mutex-ul. În schimb, punerea în aplicare a unei politici de mutex, cu o capacitate de timeout în POSIX fire necesită utilizarea unei variabile mutex și o variabilă condiție, algoritmul rezultat este mult mai complexă pentru a scrie și de a menține, și se suportă de cel puțin de două ori la fel de mult ca de performanță aeriene de un mutex fără o capacitate de timeout. Această aeriene de performanță suplimentară sugerează că, dacă unii programatori decid că necesită o politică mutex cu o capacitate de timeout, atunci acestea ar trebui să-l pună în aplicare ca un nou SPG, să zicem, TimeoutMutex, mai degrabă decât adauga capacitatea de expirare a politicii Mutex existent. În acest fel, programatorii pot utiliza politica TimeoutMutex pe puținele ocazii când au nevoie, și pot utiliza politica mutex mai eficientă în toate alte ocazii. 7.3 Lock Ierarhiile SGP sunt utile pentru clasele sau obiectele care au de sine stătător de sincronizare. Cu toate acestea, uneori, cerințele de sincronizare de mai multe clase sunt strâns legate între ele, și are nevoie de un programator pentru a obtine lacate pe două (sau mai multe) obiecte înainte de efectuarea unei sarcini. Necesitatea de a achiziționa lacate asupra mai multor obiecte în același timp este denumit în mod obișnuit ca o ierarhie de blocare. Încercarea de a dobândi o ierarhie de blocare poate duce la impas, dacă face incorect. Algoritmi pentru dobândirea ierarhiile de blocare în condiții de siguranță sunt în afara domeniului de aplicare al acestei lucrări, dar pot fi găsite în altă parte []. Punct de notat este faptul că algoritmii de dobândire a ierarhiilor de blocare necesită condiții de siguranță de acces neîngrădit la primitivele de blocare. Acest lucru este în opoziție cu SPG, care încapsulează complet primitivele care stau la baza de sincronizare. 8 GSP Clasa Biblioteca Această lucrare însoțește o bibliotecă de clase SPG. Puteți descărca această lucrare, precum și biblioteca sa din www.CiaranMcHale.com/download. Biblioteca pune în aplicare toate SGP discutate în această lucrare, care este, GSP_Mutex, GSP_RW, GSP_ProdCons și GSP_BoundedProdCons.Biblioteca pune în aplicare aceste SGP pentru următoarele pachete: fire fire fire Solaris, DCE, firele POSIX și fire de Windows. Implementari ale acestor dummy SGP pentru non-filetate sisteme sunt, de asemenea, furnizate; acest lucru face posibil pentru a scrie o clasa care poate fi utilizat în aplicații, atât secvențiale și multi-threaded. Toate clasele sunt puse în aplicare SPG cu codul de linie în fișierele antet. Din aceasta cauza, pentru a face uz de o SPG ai nevoie doar # include fișierul header corespunzător, nu există nici o bibliotecă GSP a conecta în aplicația dumneavoastră.Numele fișierului antet pentru un GSP este același ca și numele clasei SPG, dar scrise cu litere mici. De exemplu, fișierul antet pentru clasa GSP_RW este "gsp_rw.h". Ar trebui să utilizați opțiunea-D <symbol_name> dvs. pe C + + compilator pentru a defini una din următoarele simboluri:
|
Sciencespaces
© 2024 Created with the assistance of @ReuN Support Team.
All rights protected.
|
|