Să începem cu una simplă: să vorbim despre modul în care o sarcină poate aștepta finalizarea unei alte sarcini sau finalizarea unui proces.
Dacă aveți nevoie pentru a face o sarcină de așteptare pentru îndeplinirea altor sarcini care rulează în cadrul aceluiași proces, ar putea fi tentat să efectueze o astfel de așteptare de o variabilă globală, conținutul care se modifică odată cu finalizarea celei de a doua sarcină. Prima sarcină poate apoi să interogheze conținutul acestei variabile globale într-o buclă, așteptând momentul în care se schimbă.
Dezavantajul evident al acestei abordări este că sarcina de așteptare primește canale de timp CPU. Acest lucru reduce performanța generală a sistemului, deci trebuie să găsiți o altă modalitate de a îndeplini așteptările. Ar fi bine să organizați așteptarea astfel încât planificatorul de sarcini să nu aloce timpul procesorului la sarcini care așteaptă ceva.
Se așteaptă încheierea unei sarcini sau a unui proces
Dacă trebuie să așteptați finalizarea unei sarcini sau a unui proces, este mai bine să utilizați funcția WaitForSingleObject XE "WaitForSingleObject" pentru aceasta. cu care sunteți deja familiar de la aplicațiile anterioare.
Prototipul funcției WaitForSingleObject este prezentat mai jos:
Ca parametru hObject această funcție, trebuie să treacă ID-ul obiectului pentru care așteaptă, și ca un parametru dwTimeout - timeout în milisecunde (așteptați poate fi infinit, în cazul în care timp pentru a specifica valoarea INFINIT).
Multe facilități sunt sistem de operare Microsoft Windows NT, cum ar fi identificatori de sarcini, procese, fișiere, pot fi în două stări - marcate (semnalizate) și nemarcat (nonsignaled). În special, în cazul în care sarcina sau proces este în stare (de exemplu, activitatea) de funcționare, identificatorii corespunzători sunt în stare nemarcate. Atunci când sarcina sau procesul își încheie activitatea, identificatorii lor sunt marcați (adică trec la starea marcată).
Dacă sarcina creează o altă sarcină sau proces, și apoi apelează funcția WaitForSingleObject XE "WaitForSingleObject". specificând ID-ul sarcinii create ca primul parametru, iar INFINITE XE "INFINITE" ca al doilea parametru. sarcina părintelui intră într-o stare de așteptare. Acesta va fi în starea de așteptare până când sarcina sau procesul copilului își va încheia activitatea.
Rețineți că funcția WaitForSingleObject nu verifică starea ID-ul de activitate al procesului de copil, sau într-o buclă, de așteptare pentru ea (sau ei) finalizare. O astfel de acțiune ar conduce la alocarea cuantumului timpului CPU la sarcina părintelui, ceea ce este exact ceea ce am dori să evităm. În schimb, funcția WaitForSingleObject rapoarte sarcini planificatorul punerea în aplicare a sarcinii-mamă, numim această funcție, este necesar să se suspende până când sarcina copilului sau proces nu este încheiat activitatea.
Atunci când decideți dacă să alocați fragmentul de timp CPU sarcinei părinte, planificatorul verifică starea sarcinii copilului. Suma temporală este alocată de programator sarcinii părinte numai dacă sarcina copilă și-a finalizat activitatea și identificatorul său este în stare marcată. Un astfel de test nu necesită mult timp și, prin urmare, nu duce la o scădere semnificativă a performanței sistemului.
În Fig. 4.1 arată modul în care sarcina numărul 1 așteaptă încheierea sarcinii cu numărul 2 care are identificatorul hThread2.
Săgeata punctată arată un eveniment care duce la terminarea așteptării. Acest eveniment este, evident, finalizarea sarcinii hThread2.
Ca un exemplu al funcției WaitForSingleObject XE „WaitForSingleObject“ să aștepte pentru procesul de copil, ia în considerare un fragment ușor modificată a cererii inițiale de text pstart descris în capitolul precedent:
Aici, sarcina principală care utilizează funcția CreateProcess pornește procesul. Identificatorul acestui proces este stocat în câmpul hProcess al structurii pi. Dacă procesul a început cu succes, sarcina principală a aplicației își suspendă activitatea până când procesul de funcționare își încheie activitatea. Pentru a face acest lucru, el numește funcția WaitForSingleObject XE "WaitForSingleObject". dându-i ID-ul procesului de rulare.
Dacă procesul părinte nu este interesat de soarta procesului său copil, funcția WaitForSingleObject nu este necesară. În acest caz, sarcina principală poate închide imediat identificatorii procesului copil și sarcina principală a procesului copil, tăind "legăturile părinte":
Procesul început în acest fel se numește detașat. El își va trăi viața indiferent de stadiul procesului care la lansat.
Acum, să vorbim despre codul de completare al funcției WaitForSingleObject.
În cazul unei erori, funcția returnează valoarea WAIT_FAILED. Codul de eroare poate fi obținut cu funcția GetLastError.
Dacă funcția reușește, poate reveni la una din următoarele trei valori: WAIT_OBJECT_0, WAIT_TIMEOUT sau WAIT_ABANDONED.
Dacă starea identificatorului obiectului pentru care a fost așteptată a fost marcată, funcția returnează valoarea WAIT_OBJECT_0. Astfel, când așteptăm ca sarcina să termine și sarcina terminată "într-un mod natural", funcția WaitForSingleObject XE "WaitForSingleObject" returnează exact această valoare.
Dacă timpul de expirare specificat în al doilea parametru al funcției WaitForSingleObject a expirat, dar obiectul nu a intrat niciodată în starea marcată, valoarea WAIT_TIMEOUT este returnată. Evident, cu așteptare infinită, nu veți obține niciodată acest cod de ieșire.
Codul de completare WAIT_ABANDONED este returnat pentru obiectul de sincronizare de tipul Mutex (despre care vom discuta mai târziu), care nu a fost lansat de sarcina care și-a finalizat activitatea. Astfel, în acest caz, așteptarea a fost anulată și obiectul corespunzător (Mutex) nu a intrat în starea marcată.
Se așteaptă efectuarea mai multor sarcini sau procese
Adesea, o sarcină ar trebui să aștepte îndeplinirea mai multor sarcini sau procese sau una din mai multe sarcini sau procese. Această așteptare nu este dificil de realizat cu funcția WaitForMultipleObjects, prototipul căruia este prezentat mai jos:
În cazul în care conținutul parametrului fWaitAll este TRUE, sarcina este transferată în starea de așteptare, atâta timp cât toate sarcinile sau procesele, identificatorii sunt stocate într-o matrice lphObjects, au finalizat munca lor. În cazul în care valoarea fWaitAll este FALSE, așteptarea se oprește când una dintre sarcinile sau procesele specificate se termină. Pentru a îndeplini așteptările infinit, la fel ca în cazul funcției WaitForSingleObject XE „WaitForSingleObject“. Trebuie să treceți valoarea INFINITE prin parametrul dwTimeout.
Cum se utilizează această funcție?
Un exemplu poate fi găsit în codul sursă al aplicației MultiSDI descrisă mai devreme.
Mai întâi, trebuie să pregătiți o matrice pentru stocarea identificatorilor de sarcini sau a proceselor, finalizarea cărora trebuie să așteptați:
După aceea, identificatorii sarcinilor sau proceselor care rulează trebuie să fie scrise în matrice:
În acest caz, sarcina care a cauzat funcția WaitForMultipleObjects va intra în starea de așteptare până când toate cele trei sarcini și-au terminat activitatea.
Funcția WaitForMultipleObjects poate reveni la una din următoarele valori:
· WAIT_FAILED (pe eroare);
· WAIT_TIMEOUT (dacă perioada de expirare a expirat);
· O valoare între WAIT_OBJECT_0 la (WAIT_OBJECT_0 + cObjects - 1), care, în funcție de parametrul conținut fWaitAll sau înseamnă că toate identificatorilor preconizate a trecut în stare marcată (dacă fWaitAll a fost egal cu TRUE), fie această valoare, dacă o scad WAIT_OBJECT_0 constantă, egală cu ID-ul de index al obiectului marcat în lphObjects matrice identfikatorov.
· O valoare între WAIT_ABANDONED_0 la (WAIT_ABANDONED_0 + cObjects - 1), în cazul în care așteptările pentru obiectele Mutex a fost anulată. Indicele obiectului corespunzător din lphObjects matrice poate fi determinată prin scăderea valorii WAIT_ABANDONED_0 codul retur.