Dragi cititori, care (încă)
nu știu cine este și ce Dzh.Rihter SDK.
Procese în Windows
Un proces denumit în mod obișnuit ca o instanță a unui program care rulează.
Deși la prima vedere, se pare că noțiunea de program și procesul este aproape la fel, ele sunt în mod fundamental diferite unele de altele. Programul este un set static de instrucțiuni, iar procesul este un set de resurse și a datelor utilizate în timpul execuției programului. Procesul în Windows este format din următoarele componente:
- structură de date care conține toate informațiile despre acest proces, inclusiv o listă de deschis se ocupă de o varietate de resurse de sistem, un ID unic proces, informații statistice diferite, etc.;
- Identificatorul de flux unic;
- Conținutul set de registre procesor care reflectă starea procesorului;
- Două stive, dintre care unul este utilizat atunci când fluxul în modul kernel, iar celălalt - în modul de utilizare;
- Zona închisă de memorie numită memorie flux local (fir de stocare locală, TLS) și subsistemele utilizate, biblioteci run-time și DLL.
Că toate firele de lucru, sistemul de operare atribuie fiecare dintre ele un anumit procesor. Astfel, creând iluzia de fire simultane de execuție (desigur, paralelismul adevărat posibil pentru calculatoare multiprocesor). În sistemul Windows este pus în aplicare de planificare preemptive, bazată pe priorități, care rulează întotdeauna fluxul cu cea mai mare prioritate, gata pentru a rula. Selectate pentru a efectua fluxul de lucru pentru o anumită perioadă, numită cuantică. Quantum determină cât de mult fluxul va rula până când sistemul de operare nu va întrerupe. La sfârșitul sistemului de operare cuantic verifică dacă gata pentru a efectua un alt fir cu aceeași (sau mai mare), nivelul de prioritate. În cazul în care aceste fluxuri nu s-au dovedit a fi firul curent este alocat un alt cuantic. Cu toate acestea, firul nu se poate folosi din plin cuantumul acesteia. De îndată ce celălalt fir cu prioritate mai mare este gata pentru a rula, fluxul de curent este forțat, chiar dacă cuantumul acesteia nu a expirat.
Ori de câte ori are loc o întrerupere de timer-ul cuantei de flux deduse 3, și așa mai departe până când ajunge la zero. timer Răspuns în frecvență depinde de platforma hardware. De exemplu, pentru cele mai multe sisteme x86 cu un singur procesor este 10ms, și în cele mai multe sisteme multiprocesor x86 - 15ms.
în Windows Programarea este fir de nivel, mai degrabă decât procese. Se pare clar, deoarece procesele în sine nu sunt îndeplinite, dar oferă doar resurse și un context pentru executarea filetelor. Prin urmare, atunci când se planifică fluxuri, sistemul nu acorde atenție la ceea ce fac parte ce proces. De exemplu, dacă procesul A are 10 fire, și executabile procesul B - două fluxuri 12 și toți au aceeași prioritate, fiecare fir primește 1/12 timp CPU.
În Windows există un nivel de 32 de prioritate, de la 0 la 31. Acestea sunt grupate după cum urmează: 31 - 16 niveluri de timp real; 15 - 1 nivele dinamice; 0 - nivel sistemic rezervat pentru reducerea la zero pagini flux (fir pagini zero).
Atunci când se creează un proces, i se atribuie una dintre cele șase priorități ale claselor:
clasa de timp real (valoare 24)
Clasa de ridicată (valoare 13)
Mai sus de clasă normală (valoarea 10)
clasa normală (valoarea 8),
Mai jos clasă normală (valoarea 6),
și clasa Idle (valoarea 4).
afinitate Procesor
Dacă sistemul de operare se execută pe o mașină care are mai mult de un procesor, firul implicit se execută pe orice procesor disponibil. Cu toate acestea, în unele cazuri, un set de procesoare pe care fluxul poate manipula, poate fi limitat. Acest fenomen se numește o legare la procesoarele (afinitate procesor). Puteți schimba programul de procesor de afinitate prin intermediul funcțiilor Win32-planificare.
- Deschide un fișier de imagine (EXE), care va fi efectuată în acest proces. Dacă fișierul executabil nu este o aplicație Win32 validă, suportul de imagine este solicitată (imagine de sprijin) pentru a rula acest program. De exemplu, în cazul în care fișierul executabil cu extensia .bat, executați cmd.exe etc.
- Win32 obiect creează un „proces“.
- Se creează un flux primar (stivă, „flux“ și obiectul contextului).
- Subsistemul Win32 este notificat unui nou proces și fir.
- Acesta începe executarea fluxul principal.
Un proces încetează atunci când:
- Funcția de intrare a revenit controlul fluxului primar.
- Unul dintre fluxurile de proces numit funcția ExitProcess.
- Fluxul de un alt proces numit funcția TerminateProcess.
Exemplul 1: Programul creează un proces de „calculator“.
Kernel obiect este, de fapt, structura creată de kernel și disponibile numai pentru el. Aplicația utilizator se transmite numai descriptor (mâner) al obiectului, și controlează nucleu obiect folosind API funcții Win32.
Cum se poate suspenda fluxul? Există mai multe moduri. Iată câteva dintre ele.
Funcția Sleep () suspendă fluxul de funcționare un număr predeterminat de milisecunde. Dacă argumentul pe care îl specificați 0 ms, apoi să se întâmple în continuare. Hraneste renunțe la cuantumul acesteia de timp CPU, dar va apărea imediat în lista de fire gata pentru a rula. Cu alte cuvinte, se întâmplă fluxuri de comutare intenționate. (Sau, mai degrabă, o încercare de a schimba. La urma urmei, următoarea pentru un fir de executie poate fi bine la fel.)
WaitForSingleObject () funcția suspendă firul până la până când unul dintre cele două evenimente:
- timeout expiră;
- obiectul de așteptat intră în starea de alarmă (semnalizate).
Prin valoare de returnare este posibil să se înțeleagă care dintre cele două evenimente se întâmplă. Asteptati-va o asteptati-ajutor funcții pot fi cele mai multe obiecte de nucleu, de exemplu, obiectul „proces“ sau „flux“ pentru a determina momentul în care termina munca.
Funcția WaitForMultipleObjects este trecut o serie de obiecte dintr-o dată. Acesta poate fi de așteptat de funcționare o dată toate obiectele, sau oricare dintre ele.
Exemplul 2. Programul creează două flux identic și așteaptă finalizarea.
Curente pur și simplu a scrie un mesaj de tip text, care le este livrat în timpul inițializării.
Mutex (mutex) este kernel-ul obiectele care sunt create CreateMutex) funcția (. Mutex se află în două state - Sport și liber. Mutex este bun pentru a proteja identitatea resursei în același timp, se referă la ea de fire diferite.
Exemplul 3. Să presupunem că programul folosește o resursă, cum ar fi un tampon de fișier sau de memorie. Funcția WriteToBuffer () se numește din fire diferite. Pentru a evita conflictele, în timp ce se referă la buffer-ul din fire diferite, folosim un mutex. Înainte de a porni la tamponul se așteaptă mutex.
Semaforul (a semaforului) a creat funcția CreateSemaphore (). Este foarte similar cu un mutex, dar spre deosebire de el într-un semafor are un contor. Semafor deschis în cazul în care contorul este mai mare decât 0 și închis atunci când contorul este 0. semaphore în general „anexați“ seturi echivalente de resurse (componente), o astfel de coadă, lista, etc.
Exemplul 4 Un exemplu clasic este utilizarea unui element de coadă semafoarelor, care este tratat cu mai multe fire. Curente „pick up“ elemente din coadă. În cazul în care coada este goală, fluxul trebuie să „doarmă“, așteptând apariția unor elemente noi. Pentru a ține cont de elementele din coadă folosind un semafor.
Notă. În acest exemplu, noi credem că procedurile în sine adăugarea unui element la coada, și se scoate din coada sunt în siguranță în ceea ce privește multithreading. Nu ne vom ocupa de încă detaliile punerii lor în aplicare. ne vom uita la acest lucru în exemplul 9 în detaliu.
Evenimente (Eveniment), precum și mutex are două stări - set și aruncat. Evenimentele sunt manual de resetare și AUTORESET. Când un fir de așteptare (wait-funcție returnează de management) eveniment AUTORESET, un astfel de eveniment este resetat automat. În caz contrar, evenimentul trebuie să fie resetat manual, prin apelarea funcției ResetEvent (). Să presupunem că mai multe fluxuri se așteaptă la aceleași evenimente și lucrările de evenimente. În cazul în care acest lucru a fost un eveniment cu AUTORESET, acesta va permite să lucreze doar un singur fir (pentru că imediat după întoarcerea sa de la evenimentul de așteptare funcție este resetat automat!), Și alte fire va aștepta. În cazul în care acest lucru a fost un eveniment cu un manual de resetare, atunci toate firele vor primi de control, iar evenimentul va rămâne în starea set până când un fir de apeluri ResetEvent ().
Exemplul 5: Acesta este un alt exemplu al unei aplicații multithreaded. Programul are două fluxuri; una pregătește datele, iar al doilea se referă la server. Este rezonabil să paraleliza munca lor. Aici fluxuri ar trebui să funcționeze la rândul său. În primul rând, primele date flux preparare porțiune. Apoi trimite un al doilea flux, iar primul între timp pregăti porțiunea următoare, și așa mai departe Pentru o astfel de sincronizare nevoie de două AUTORESET tonomat.
PulseEvent () funcție setează evenimentul și apoi pune-l din nou într-o stare de resetare; numindu-l echivalent cu apelarea SetEvent secvență () și ResetEvent (). În cazul în care PulseEvent chemat pentru eveniment pentru a reseta manual, toate firele de așteptare de pe acest obiect, pentru a primi de control. Atunci când apelați pentru evenimentul PulseEvent AUTORESET trezește doar unul dintre firele de așteptare. Și dacă nici unul dintre fluxurile care nu sunt în așteptare pentru obiectul evenimentului, apelul funcției nu are niciun efect.
Exemplul 7. realizează funcția NextFrame () pentru exemplul anterior pentru a derula manual fișierul cu cadru.
obiectul cel mai sofisticat nucleu pentru sincronizare - Poate, cronometre de așteptat. au apărut, începând cu Windows 98. Temporizatoare sunt funcții CreateWaitableTimer și sunt, precum și evenimente, AUTORESET fără ea. Apoi, cronometrul ar trebui să fie setată funcția SetWaitableTimer. Cronometrul merge într-o stare de alarmă atunci când expiră timpul de expirare. Anulare „ticăie“ funcția temporizator poate CancelWaitableTimer. Este demn de remarcat faptul că puteți specifica funcția de apel invers la setarea cronometrului. Acesta va fi executat atunci când expiră cronometrul.
Exemplu Program Service 8. Scriere folosind WaitableTimer'y. Serviciul va srabatyvat ori pe zi la ora 8 dimineața și „pikat“ de 10 ori. Noi folosim cele două cronometre, una cu un apel invers-funcție.
sectiuni critice. Sincronizarea în modul de utilizare.
secțiunea critică te asigură că bucățile de cod de program, împrejmuită nu vor fi efectuate simultan. Strict vorbind, secțiunea critică nu este kernel-ul de obiect. Este o structură care cuprinde un număr de steaguri și un fel (nu este important) obiectul nucleu. La intrarea în secțiunea critică mai întâi verificat steaguri, iar în cazul în care se dovedește că acesta este deja ocupat de un alt fir, atunci de obicei așteptați-funcția. O secțiune critică este notabil faptul că pentru a testa, ocupat sau nu, programul nu intra în modul de kernel (nu deține așteptați-funcție) și verificate doar steaguri. Din acest motiv, se crede că sincronizarea cu ajutorul secțiunilor critice ale cel mai rapid. Această sincronizare se numește „sincronizare în modul de utilizare“.
Exemplul 9. Luați în considerare din nou toate elementele. Una dintre opțiunile pentru punerea sa în aplicare - o listă dublu-linked. Din punctul de vedere al operației de filetare este periculos să adăugați și să eliminați elemente din coadă. Există posibilitatea ca mai multe fire în același timp, începe să reconstruiască indecși și conectivitate cozile perturbate. Pentru a evita acest lucru, utilizați o secțiune critică.
Descriptorii obiect kernel depind de procesul particular (proces specific). Pur și simplu pune, mâner obiect obținut într-un singur proces, nu este semnificativ în cealaltă. Cu toate acestea, există modalități de a lucra cu aceleași obiecte nucleu de diferite procese.
În primul rând, este moștenirea descriptor. La crearea unui obiect, puteți specifica dacă va fi moștenită de descriptor copil (generate de acest proces) proces.
În al doilea rând, duplicat descriptor. Funcția DuplicateHandle duplicat obiect descriptor de la un proces la altul, adică, De fapt, ia recordul în tabel se ocupă de un singur proces creează o copie a acesteia, pe de altă masă.
Și, în sfârșit, denumirea obiectului nucleu. La crearea unui nucleu pentru obiectul de sincronizare (mutex semaphore temporizator sau eveniment de așteptat) poate selecta numele său. Acesta trebuie să fie unic în sistem. Apoi, un alt proces poate deschide obiectul nucleu, specificând funcțiile Open ... (OpenMutex, OpenSemaphore, OpenWaitableTimer, OpenEvent) numele.
De fapt, atunci când apelați funcția Creare. (), Sistemul verifică mai întâi pentru a vedea dacă există deja un obiect nucleu cu același nume. Dacă nu, se creează un nou obiect. Dacă da, kernel-ul verifică tipul drepturilor de obiect și de acces. În cazul în care tipurile nu se potrivesc, sau apelantului nu are drepturi depline de acces la obiect, apelați Create ... funcția eșuează și returnează NULL. Dacă totul merge bine, se creează doar un nou descriptor (mâner) obiect nucleu deja existent. Funcția de cod GetLastError întoarce () poate înțelege ce sa întâmplat: pentru a crea un obiect nou, sau Create () a returnat unul existent.
Prin urmare, pentru a sincroniza fire în cadrul diferitelor procese pot fi exact la fel ca și în același. Doar trebuie să transmită în mod corect descriptorul obiect de sincronizare de la un proces la altul prin oricare dintre metodele enumerate mai sus.
Exemplul 10. Multe aplicații la pornire a verifica dacă o altă instanță a programului de funcționare. Modul standard de a pune în aplicare acest test - folosind un mutex numit.
Alte mecanisme (prize, pipe)
Canalele sunt utilizate pentru transferul de date într-o singură direcție între procesele părinte și copil sau între două procese copil. citește funcționare / scriere la un canal similar cu operațiunile similare de pe fișiere.
canale de nume sunt utilizate pentru comunicare bidirecțională între procesul de server și unul sau mai mulți proces client. Ca canale anonime care le folosesc interfata faylopodobny dar, spre deosebire de primul, este de asemenea potrivit pentru schimbul de date prin rețea.
Socket - un obiect abstract pentru a se referi la unul dintre capetele conexiunii la rețea, inclusiv pe Internet. prize de Windows sunt de două tipuri: socketuri datagramă fluxuri. Windows Sockets Interface (WinSock) se bazează pe versiunea BSD-socket, dar există, de asemenea, extensii care sunt specifice pentru Windows.
Mesaje în Windows (mesaje fereastra)
Vorbind despre Windows să nu mai vorbim despre concepte, cum ar fi ferestre (geamuri), mesaje (mesaj), coada de mesaje (Message Queuing) etc.
Fereastra - aceasta (dreptunghiular) suprafata a ecranului care afișează informațiile de aplicație (în cazul în care este vizibil, desigur), și primește informații de la utilizator. Pentru Windows aparțin fluxurilor. Un flux creează o fereastră considerată proprietarul acestei ferestre. Fluxul poate fi proprietarul de mai multe ferestre.
Mesajele de control Windows. Toate evenimentele din fereastra, urmat de trimiterea unui mesaj la el, crearea și distrugerea de ferestre, de intrare tastatură, mișcarea mouse-ului, revopsire și ferestre în mișcare etc. fereastra Notificările pot fi trimise atât aplicațiile de utilizare a sistemului și. Fiecare fereastră este atribuită o funcție numită procedură de fereastră (procedura de fereastră), și care se numește atunci când procesarea mesajului.
Mesajele pot fi trimise nu numai la fereastră, dar cele mai multe flux. Fiecare fir care deține fereastra are o coadă de mesaje. De obicei, firul care deține fereastra, doar pe cei implicați, care procesează mesajele trimise la ferestrele sale.
În cazul în care obiectul se ocupă de nucleu dependent de proces, mânere de fereastră sunt unice în cadrul Deskop. Prin urmare, un proces nu este dificil de a obține și de a folosi un mâner fereastră care aparține alt flux de proces.
Trimiterea același mesaj de la o aplicație la alta nu este celălalt, ca o modalitate de comunicare inter-proces.
Exemplul 12. Programul găsește fereastra cu titlul „Calculator“ și se închide prin trimiterea WM_CLOSE.