Prenos datotek iz interneta. Zaščita skupnih podatkov

5.6. Kondenzacija toka obremenitve

Po pregledu tehnik stiskanja, veriženja, predpomnjenja in paralelizacije bi bilo smiselno zastaviti naslednje vprašanje: Kolikšen del strani naj se naloži z glavno datoteko HTML in kolikšen del naj naloži samo zunanje datoteke?

Testno okolje je bilo sestavljeno v obliki ene strani, za katero so bile uporabljene različne optimizacijske tehnike (hkrati je bil dosežen realni pospešek za nalaganje poljubne strani in prikazano, kako vse te tehnike dejansko vplivajo na hitrost nalaganja strani).

Poleg tega so bili izvedeni teoretični izračuni za določitev optimalne porazdelitve obremenitve po stopnjah, ob upoštevanju vseh vidikov.

Iz knjige Boost your website avtor Matsievsky Nikolaj

Končna tabela Spodaj so vsi rezultati optimizacije za posamezno stran. Prenos preizkušen pri povezavi 100 Kb/s, skupno število začetnih objektov: 23. Številka koraka Opis Skupna velikost (kb) Čas prenosa (ms) 1Navadna stran. Nič ni stisnjeno

Iz knjige Iptables Tutorial 1.1.19 avtorja Andreasson Oskar

Iz knjige PROGRAMSKA OPREMA ZA VGRADNE SISTEME. Splošne zahteve za razvoj in dokumentacijo avtor Gosstandart Rusije

Iz knjige Linux za uporabnike avtor Kostromin Viktor Aleksejevič

2.4.3. Možnosti nalaganja Torej, po mojem mnenju je izbira možnosti nalaganja naslednja: Če imate nameščen Windows NT ali Windows 2000, uporabite NT Loader. Če imate Windows 95 ali Windows 98 na FAT16 in ne želite namestiti zagonskega programa iz drugega operacijskega sistema ali

Iz knjige 200 najboljših programov za internet. Priljubljena vadnica avtor Krainsky I

8.2. Postopek za nalaganje OS Linux Najprej je treba opozoriti, da vse, kar bo obravnavano v tem razdelku, velja za distribucijo Red Hat in njene analoge. Druge distribucije (npr. Debian) imajo lahko drugačne postopke prenosa.

Iz knjige Asterisk™: Prihodnost telefonije, druga izdaja avtor Meggelen Jim Wang

Upravljalniki prenosov Nič ne moti uporabnika interneta bolj kot počasne hitrosti prenosa. Ta problem je mogoče rešiti na različne načine. Lahko uporabite različne brskalnike in izberete najhitrejšega, ali pa prihranite denar in kupite drag modem, ki bo samozavestno

Iz knjige Arhitektura TCP/IP, protokoli, implementacija (vključno z različico IP 6 in varnostjo IP) avtorja Faith Sydney M

Protokol, ki se uporablja za prenos Telefoni Polycom lahko svojo konfiguracijo prenesejo z enim od treh protokolov: TFTP, HTTP in FTP. Že takoj na začetku bi vas radi prosili, da se izogibate TFTP. Ne zagotavlja potrebne varnosti in telefon ne more uporabiti informacij o datumu

Iz knjige Samostojni priročnik za delo na Macintosh avtorica Sofia Skrylina

11.11 Možnosti zagona Možnosti v tabeli 11.1 so lahko vsebovane v odzivih BOOTP ali DHCP, možnosti v tabeli 11.2 pa se lahko uporabljajo samo v DHCP.

Iz knjige Prvi koraki z Windows 7. Priročnik za začetnike avtor Kolisničenko Denis N.

4.1.6. Mapa Prenosi S klikom na gumb Shrani, ki se nahaja v glavi pisma, se pripete datoteke samodejno shranijo v mapo Prenosi, ki se nahaja v domači mapi uporabnika (slika 4.21). Odprete jo lahko kot vsako mapo v oknu

Iz knjige Linux: The Complete Guide avtor Kolisničenko Denis Nikolajevič

2.4.4. Omogočanje zagona z DVD-ja Za zagon z namestitvenega diska Windows morate spremeniti vrstni red zagona v nastavitvah BIOS-a (tako da se sistem zažene z DVD-ja in ne s trdega diska). V primeru namiznega računalnika morate za vstop v BIOS Setup običajno samo pritisniti tipko takoj,

Iz knjige Adobe Flash. Ustvarite arkadne, uganke in druge igre z ActionScript avtor Rosenzweig Gary

9.1.2. Nadaljujte z nalaganjem. Začetni demon Od trenutka, ko je jedro naloženo, nadzira začetni zagonski proces sistema sam sistem. Prvi, ki prejme nadzor, je postopek samodejnega zagona jedra. Določa količino razpoložljivega RAM-a, vrsto in hitrost procesorja,

Iz knjige Kako promovirati in oglaševati spletno stran na internetu avtor Zagumenov Aleksander Petrovič

Zaslon za nalaganje Medtem ko si morate vedno prizadevati za čim manjšo velikost končne datoteke, boste verjetno imeli videoposnetke, ki se pri delu prek modema naložijo več kot nekaj sekund. Če je igra velika na stotine kilobajtov, bodo nekateri uporabniki

Iz knjige Linux skozi oči hekerja avtor Flenov Mihail Evgenijevič

Čas nalaganja strani Počasno nalaganje spletnih strani pogosto moti uporabnike in posledično zmanjša promet na strežniku. Ker ne želijo izgubljati časa, mnogi raje iščejo informacije v drugih virih. Zato je zelo pomembno, da ne varčujemo z materialom

Iz knjige Windows 10. Skrivnosti in naprava avtor Almametov Vladimir

3.2.4. Zanimive nastavitve zagona Poglejmo si nekaj datotek, ki sicer rahlo vplivajo na zagon Preden se prikaže poziv za vnos gesla, se na zaslonu prikažejo besedilne informacije in razlaga. Najpogosteje tukaj razvijalec napiše ime distribucije

Iz avtorjeve knjige

10.3.2. Nadzor nad nalaganjem datotek Nalaganje datotek je najnevarnejša priložnost za strežnik. Vsak uporabnik naj ima pravico dostopa le do svojega imenika. Kaj storiti, da bodo lahko z datotekami delali tudi anonimni uporabniki? V tem primeru morate

Bistvo problema.

Vaša delujoča aplikacija na neki točki začne aktivno nalagati CPU, tester vas pokliče in vas prosi, da to popravite!

Kakšna so običajna dejanja programerjev v tem primeru?

  • Prosijo, da ga lokalizirajo, če deluje, potem je vprašanje časa za rešitev težave.
  • Začne se dodajanje dnevnikov, števcev prehodov in podobno. Vse je dano testerju ali stranki z zahtevo po reprodukciji in vrnitvi dnevnika v analizo. Dobro je, če ga lahko reproducirate in vse bo postalo jasno.
  • Predpostavimo čas, ko je "vse delovalo" in poiščite možne razloge na podlagi sprememb v sistemu za nadzor različic.


kako lažje kaj narediti v tem primeru?

pomeni, da so se nekatere niti za obdelavo podatkov prebudile/zagnale in začele aktivno opravljati svoje delo ali pa so včasih le šle v ciklih. S poznavanjem izvajalnega sklada v času nalaganja lahko z veliko verjetnostjo razumete razlog za takšno vedenje.

Kako ga lahko prepoznamo, ker nismo pod debuggerjem??Osebno uporabljam pripomoček Raziskovalec procesov kar vam omogoča ogled seznama niti in njihovega sklada . Namestitveni program ni potreben.

Za dokaz sem zagnal svojo aplikacijo z imenom procesa " Qocr.Application.Wpf.exe", v katerem dodano Lažne koda neskončne zanke. Zdaj pa poiščimo razlog za nalaganje jedra brez razhroščevalnika. Za to grem v lastnosti procesa , Nadalje:

  1. Pojdite na zavihek Niti in vidimo, da obstaja 1 tok, ki se naloži za 16 % procesor.
  2. Izberite ta tok in kliknite Stack Odprlo se je okno "Sklad za nit". ID".
  3. V oknu vidimo, da je bil naš tok ustvarjen tukaj Qocr.Application.Wpf.exe!<>c. b__36_1+0x3a in trenutno kliče GetDirectories od metode InitLanguages().

Zgornja dejanja na sliki bom prikazal s puščicami:

Z odpiranjem izvorne kode programa in odpiranjem metode InitLanguages lahko vidite mojo lažno kodo. Če poznate te podatke, in sicer lokacijo vzmetenja, lahko že ukrepate.

Koda sklada (iz zgornjega primera), ki povzroča neskončno zanko (lahko preverite):

Private void InitLanguages() ( new Thread (() => ( while (true) ( ​​var dir = Directory .GetDirectories(@"C:\"); ) ; )).Start(); )

Muha v sodu medu.

Če se odločite za uporabo zgornje metode, morate vedeti dve stvari:
  1. Tokovi ustvarjeni CLR(ustvarjeno v kodi .MREŽA aplikacije) po zaustavitvi ne nadaljujejo z izvajanjem. Posledično se nit ustavi in ​​visi, dokler se program ne zažene znova.
  2. Če izvajalni sklad ne vsebuje koristnih informacij, se je vredno ustaviti in si sklad večkrat ogledati. Verjetnost, da bi naleteli na točko zanke, je zelo velika.

1.1. Definicija toka

Tok v sistemu Windows objekt jedra, ki mu operacijski sistem dodeli procesorski čas za izvajanje aplikacije. Vsaka nit ima v lasti naslednje vire:

  • koda izvršljive funkcije;
  • nabor procesorskih registrov;
  • sklad za izvajanje aplikacije;
  • sklad za delovanje operacijskega sistema;
  • dostopni žeton, ki vsebuje varnostne informacije.

Vsi ti viri tvorijo kontekst niti v sistemu Windows. Poleg deskriptorja ima vsaka nit v sistemu Windows tudi svoj identifikator, ki je edinstven za niti, ki se izvajajo v sistemu. ID-je niti uporabljajo pripomočki, ki uporabnikom sistema omogočajo sledenje dejavnosti niti.

V operacijskih sistemih Windows obstajata dve vrsti niti:

  • sistemske niti;
  • tokovi uporabnikov.

Sistemske niti izvajajo različne storitve operacijskega sistema in jih zažene jedro operacijskega sistema.

Uporabniške niti služijo za reševanje uporabniških težav in jih zažene aplikacija.

V delujoči aplikaciji obstajata dve vrsti niti:

  • delovne niti;
  • niti uporabniškega vmesnika.

Delovne niti izvajati različna opravila v ozadju v aplikaciji. Niti uporabniškega vmesnika so povezani z okni in obdelujejo sporočila, ki jih prejmejo ta okna. Vsaka aplikacija ima klicano vsaj eno nit primarni(primarni) oz glavni(glavni) tok. V konzolnih aplikacijah je to nit, ki izvaja funkcijo glavni. V aplikacijah GUI je to nit, ki izvaja funkcijo WinMain.

Funkcija ustvari nit CreateThread

funkcijo CreateThread(
lpThreadAttributes: kazalec; // varnostni atributi
dwStackSize: DWORD; // velikost sklada niti v bajtih
lpStartAddress: TFNThreadStartRoutine; // naslov funkcije
lpParameter: kazalec; // naslov parametra
dwCreationFlags: DWORD; // zastavice za ustvarjanje niti
var lpThreadId: DWORD // identifikator niti
): THandle;

Po uspešnem zaključku funkcija CreateThread vrne ročaj ustvarjeni niti in njen identifikator, ki je edinstven v celotnem sistemu. V nasprotnem primeru se ta funkcija vrne nič.

Dodelitev parametrov

lpThreadAttributes

Parameter lpThreadAttributes nastavi varnostne atribute ustvarjene niti. Dokler ne raziščemo varnosti sistema Windows, bomo ta parameter nastavili na nič pri klicanju skoraj vseh funkcij jedra sistema Windows. V tem primeru to pomeni, da bo operacijski sistem sam nastavil atribute zaščite niti s privzetimi nastavitvami.

Parameter dwStacksize definira velikost sklada, ki je dodeljena niti ob njenem zagonu. Če je ta parameter enak nič, je niti dodeljen sklad, katerega privzeta velikost je 1 MB. To je najmanjša velikost sklada, ki jo je mogoče dodeliti niti. Če vrednost parametra dwStacksize manjša od privzete vrednosti, je niti še vedno dodeljen sklad velikosti 1 MB. Operacijski sistem Windows zaokroži velikost sklada na eno stran pomnilnika, kar je običajno 4 KB.

Parameter lpStartAddress označuje funkcijo, ki jo izvaja nit.

Vidimo lahko, da je en sam parameter mogoče posredovati funkciji niti lpParameter, ki je kazalec na prazno vrsto. Ta omejitev izhaja iz dejstva, da funkcijo niti kliče operacijski sistem in ne aplikacijski program. Programi operacijskega sistema so izvršljivi moduli, zato smejo klicati samo funkcije, katerih podpis je vnaprej določen. Zato smo za niti definirali najenostavnejši seznam parametrov, ki vsebuje le kazalec. Ker funkcije niti kliče operacijski sistem, se tudi kličejo funkcije povratnega klica.

Parameter dwCreationFiags določa, v kakšnem stanju bo nit ustvarjena. Če je vrednost tega parametra 0, se funkcija niti začne izvajati takoj po ustvarjanju niti. Če je vrednost tega parametra CREATE_SUSPENDED, potem je nit ustvarjena v suspendiranem stanju. To nit lahko zaženete pozneje s klicem funkcije ResumeThread.

Parameter lpThreadId je izhod, tj. njegovo vrednost nastavi Windows. Ta parameter bi moral kazati na spremenljivko, v katero bo Windows postavil ID niti. Ta identifikator je edinstven v celotnem sistemu in ga je mogoče pozneje uporabiti za reference toka. ID niti uporabljajo predvsem sistemske funkcije in redko aplikacije. ID niti je veljaven samo za celotno življenjsko dobo niti. Ko se nit zaključi, lahko isti identifikator dodelite drugi niti.

Ko je nit ustvarjena, je njena osnovna prioriteta nastavljena kot vsota prioritete procesa, v kontekstu katerega se nit izvaja, in ravni prioritete niti. THREAD_PRIORITY_NORMAL.

Listing 1.1 prikazuje primer programa, ki uporablja funkcijo CreateThread za ustvarjanje niti in prikazuje, kako posredovati parametre funkciji, ki jo izvaja nit.

Seznam 1.1. Ustvarjanje niti s funkcijo CreateThread

Program CreateThreadd; ($APPTYPE CONSOLE) uporablja SysUtils, Windows; var n: Integer = 0; inc: celo število = 10; hThread: HWND; IDThread: DWORD; postopek Add(iNum: Kazalec); stdcall; begin Writeln("Nit je začeta"); n:= n + Integer(iNum^); Writeln("Nit je končana"); konec; begin Writeln("n = ", n); //zaženite nit Add hThread:= CreateThread(nil, 0, @Add, @inc, 0, IDThread); //Počakajte, da se nit Dodaj konča WaitForSingleObject(hThread, INFINITE); //zapri ročico niti Add CloseHandle(hThread); Writeln("n = ", n); Readln; konec.

Upoštevajte, da ta program uporablja funkcijo WaitForSingleObject, ki čaka na dokončanje niti Dodaj.

Nit se konča s klicem funkcije Izhod iz niti, ki ima naslednji prototip:

postopek Izhod iz niti(
dwExitCode: DWORD //koda zaključka niti
); stdcall;

To funkcijo lahko pokličete eksplicitno ali implicitno, ko vrnete vrednost iz funkcije niti. Ko se ta funkcija izvede, sistem pošlje sporočilo dinamičnim knjižnicam, ki jih naloži proces DLL_THREAD_DETACH, kar pomeni, da nit končuje svoje delo.

Ena nit lahko prekine drugo nit s klicem funkcije Prekini nit

funkcijo Prekini nit(
hThread:THandle; //deskriptor niti
dwExitCode: DWORD; //koda zaključka niti
): BOOL; stdcall;

Če je uspešna, funkcija Prekini nit vrne vrednost, ki ni nič, sicer - LAŽNO. funkcija Prekini nit prekine nit, vendar ne sprosti vseh virov v lasti te niti. To se zgodi, ker sistem ob izvajanju te funkcije dinamičnim knjižnicam, ki jih je naložil proces, ne pošlje sporočila, da se nit zaključuje. Posledično dinamična knjižnica ne sprosti virov, ki so bili zaseženi za delo s to nitjo. Zato je treba to funkcijo poklicati samo v nujnih primerih, ko nit visi.

Listing 1.2 je program, ki prikazuje, kako funkcija deluje Prekini nit.

Program TerminateThreadd; ($APPTYPE CONSOLE) uporablja SysUtils, Windows; var št.: Kardinal = 0; hThread: HWND; IDThread: DWORD; c: Char; b1: Boolean = True; nit postopka; stdcall; var b2: Boolean; začetek b2:= True; medtem ko b2 začne štetje:= štetje + 1; Spanje (100); // malo počivaj konec; konec; začetek hThread:= CreateThread(nil, 0, @thread, nil, 0, IDThread); medtem ko b1 do begin Write("Vnesite ""y"" za prikaz števila ali katerega koli znaka za zaključek: "); Readln(c); if c = "y" then Writeln("count = ", count) else Break; konec; //prekinitev izvajanja niti niti TerminateThread(hThread, 0); //zapri ročico niti CloseHandle(hThread); konec.

Vsaka ustvarjena nit ima števec začasne zaustavitve, katerega največja vrednost je MAXIMUM_SUSPEND_COUNT. Število začasnih zaustavitev kaže, kolikokrat je bila nit začasno začasno ustavljena. Nit se lahko izvaja le, če je njeno število prekinitev nič. V nasprotnem primeru se nit ne izvede ali pa je v limbu. Izvajanje vsake niti lahko prekinete s klicem funkcije SuspendThread, ki ima naslednji prototip:

funkcijo SuspendThread(
hThread:THandle //deskriptor niti
): DWORD; stdcall;

Ta funkcija poveča začasni števec za 1 in ob uspehu vrne trenutno vrednost tega števca. Če ne uspe, funkcija SuspendThread vrne vrednost, ki je enaka -1.

Upoštevajte, da se nit lahko tudi začasno prekine. Za to mora opraviti funkcije SuspendThread svoj psevdodeskriptor, ki ga lahko pridobite s funkcijo GetCurrentThread.

Če želite nadaljevati z izvajanjem niti, uporabite funkcijo ResumeThread, ki ima naslednji prototip:

funkcijo ResumeThread(
hThread:THandle //deskriptor niti
): DWORD; stdcall;

funkcija ResumeThread Zmanjša vrednost števca vzmetenja za 1, če je bila ta vrednost večja od nič. Če je dobljena vrednost števila prekinitev 0, se izvajanje niti nadaljuje, sicer ostane nit v limbu. Če pri klicu funkcije ResumeThread Vrednost števca prekinitve je bila 0, kar pomeni, da nit ni v stanju prekinitve. V tem primeru funkcija ne izvede nobenega dejanja. Po uspešnem zaključku funkcija ResumeThread vrne trenutno vrednost števila prekinitev, sicer -1.

Nit lahko odloži svojo izvedbo s klicem funkcije spi, ki ima naslednji prototip:

postopek spi(
dwMilisekunde: DWORD //milisekunde
); stdcall;

Enotni funkcijski parameter spi podaja število milisekund, za katere nit, ki je poklicala to funkcijo, začasno ustavi njeno izvajanje. Če je ta parameter nastavljen na 0, se nit preprosto prekine in nato nadaljuje, dokler ni drugih niti, ki čakajo na CPE čas. Če je vrednost tega parametra NESKONČNO, potem nit za vedno prekine svoje izvajanje, kar povzroči blokiranje aplikacije.

Listing 1.3 je program, ki prikazuje delovanje funkcij SuspendThread, ResumeThread in spi.

//Primer delovanja funkcij SuspendThread, ResumeThread in Sleep program SuspendThreadd; ($APPTYPE CONSOLE) uporablja SysUtils, Windows; var nCount: Cardinal = 0; dwCount: DWORD; hThread: HWND; IDThread: DWORD; c: Char; b: Boolean = True; nit postopka; stdcall; začni, medtem ko b začni nCount:= nCount + 1; Spanje (100); // zaustavi nit za 100 milisekund end; konec; začetek hThread:= CreateThread(nil, 0, @thread, nil, 0, IDThread); medtem ko b do begin Writeln("Vnos:"); Writeln(#9, """n"" za izhod"); Writeln(#9, """y"" za prikaz števila"); Writeln(#9, """s"" za prekinitev niti"); Writeln(#9, """r"" za nadaljevanje niti"); Readln(c); primer c od "n": prelom; "y": Writeln("count = ", nCount); "s": začetek //začasno zaustavi nit niti dwCount:= SuspendThread(hThread); Writeln("Število prekinitev niti = ", dwCount); konec; "r": začetek //nadaljuj nit niti dwCount:= ResumeThread(hThread); Writeln("Število prekinitev niti = ", dwCount); konec; konec; konec; //prekinitev izvajanja niti niti TerminateThread(hThread, 0); //zapri ročico niti CloseHandle(hThread); konec.

Včasih mora nit poznati svoj deskriptor, da lahko spremeni nekatere svoje značilnosti. Na primer, nit lahko spremeni svojo prioriteto. Za te namene obstaja funkcija v API-ju Win32 GetcurrentThread, ki ima naslednji prototip:

funkcijo GetCurrentThread:THandle; stdcall;

in vrne psevdo ročico trenutni niti. Psevdo-ročaj trenutne niti se od pravega ročaja niti razlikuje po tem, da ga lahko uporablja samo trenutna nit sama in ga zato lahko podedujejo drugi procesi. Po uporabi psevdo-ročaja toka ni treba zapreti. Pravi deskriptor niti lahko dobite iz psevdodeskriptorja niti; za to morate podvojiti psevdodeskriptor s klicem funkcije DuplicateHandle.

Listing 1.4 prikazuje primer programa, ki kliče funkcijo GetCurrentThread, nato pa natisne nastali psevdo-ročaj na konzolo.

//Primer delovanja funkcije GetcurrentThread program GetCurrentThreadd; ($APPTYPE CONSOLE) uporablja SysUtils, Windows; var hThread: HWND; začetek // pridobi psevdodeskriptor trenutne niti hThread:= GetCurrentThread; // pridobi psevdodeskriptor trenutne niti Writeln(hThread); Readln; konec.

Večina funkcij API-ja Win32 vrne kodo, s katero je mogoče ugotoviti, ali je bila funkcija uspešno zaključena ali ne. Če funkcija ne deluje, je povratna koda običajno lažno, nič ali -1. V tem primeru funkcija Win32 API nastavi tudi notranjo kodo napake, imenovano zadnja koda napake(koda zadnje napake) in je podprt ločeno za vsako nit. Če želite dobiti zadnjo kodo napake, morate poklicati funkcijo GetLastError, ki ima naslednji prototip:

funkcijo GetLastError: DWORD; stdcall;

Ta funkcija vrne kodo zadnje napake, sprožene v niti. S funkcijo lahko nastavite zadnjo kodo napake v toku SetLastError, ki ima naslednji prototip:

postopek SetLastError(
dwErrCode: DWORD //koda napake
); stdcall;

Če želite dobiti sporočilo, ki ustreza zadnji kodi napake, morate uporabiti funkcijo FormatMessage, ki ima naslednji prototip:

funkcijo FormatMessage(
dwFlags: DWORD; // načini oblikovanja
lpVir: Kazalec; // vir sporočila
dwMessageId: DWORD; // ID sporočila
dwLanguageId: DWORD; // identifikator jezika
lpBuffer: PChar; // medpomnilnik sporočil
nVelikost: DWORD; // največja velikost medpomnilnika za sporočilo
Argumenti: kazalec // seznam vrednosti za vstavljanje v sporočilo
): DWORD; stdcall;

Listing 1.5 prikazuje primer programa, ki kliče funkcijo FormatMessage

Program ErrorMessageBoxx; ($APPTYPE CONSOLE) uporablja SysUtils, Windows; var hHandle: THandle; procedure ErrorMessageBox; var lpMsgBuf: PChar; začetek FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER ali FORMAT_MESSAGE_FROM_SYSTEM ali FORMAT_MESSAGE_IGNORE_INSERTS, nil, GetLastError, 0, @lpMsgBuf, 0, nil); MessageBox(0, lpMsgBuf, "Napaka Win32 API", MB_OK ali MB_ICONINFORMATION); //Sprosti medpomnilnik LocalFree(Integer(lpMsgBuf)); konec; //test funkcije za prikaz sporočila o napaki na konzoli begin hHandle:= 0; //napačen klic funkcije za zapiranje ročaja, če ne CloseHandle(hHandle), potem ErrorMessageBox; konec.

Prenesite izvorno kodo. Narejeno na Delphi XE.

Uporabljena literatura: Alexander Pobegailo "Sistemsko programiranje v sistemu Windows"

Stanja niti in razporejanje


Za vsako ustvarjeno nit v sistemu so možna tri stanja:

  • stanje izvajanja, ko kodo niti izvaja procesor; na enoprocesorskih platformah je lahko v tem stanju v danem trenutku samo ena nit;
  • stanje pripravljenosti za zagon, ko je nit pripravljena nadaljevati svoje delo in čaka, da se CPE sprosti;
  • stanje čakanja na nastop nekega dogodka; v tem primeru nit ne zahteva časa procesorja, dokler se ne zgodi določen dogodek (zaključek V/I operacije, sprostitev zasedenega vira, ki ga potrebuje nit, signal iz druge niti); Pogosto se takšne niti imenujejo blokirane.
Sprememba stanja pretoka se pojavi kot posledica ustreznih ukrepov. Za te namene je priročno uporabiti naslednji diagram stanja in prehoda.

Prehode med stanji lahko opišemo na naslednji način:

  • “pripravljen” → “izvedba”: sistem v skladu z algoritmom razporejanja izbere trenutno nit za izvedbo in ji dodeli CPU
  • “teče” → “pripravljen”: nit je pripravljena nadaljevati svoje delo, vendar se sistem odloči prekiniti njeno izvajanje; Najpogosteje se to zgodi zaradi naslednjih dveh razlogov:
    • Procesorski čas, dodeljen niti, se konča;
    • med pripravljenimi za izvedbo se pojavi nit z višjo prioriteto od trenutne;
  • “izvajanje” → “čakanje”: nadaljnje izvajanje kode trenutne aktivne niti je nemogoče brez pojava nekega dogodka, zato aktivna nit prekine svoje izvajanje in jo sistem postavi v stanje čakanja (blokiran);
  • “čaka” → “pripravljen”: v sistemu se zgodi dogodek, katerega pojav čaka ena od blokiranih niti, zato sistem to nit postavi v stanje pripravljenosti (deblokira), nato pa jo sprejme v račun s strani sistema pri načrtovanju vrstnega reda zagotavljanja CPU;
  • Končno se nit lahko konča normalno ali nenormalno, nakar sistem odstrani svoj ročaj iz svoje notranje strukture in tako nit preneha obstajati.
Več niti je lahko v stanju pripravljenosti in čakanju, zato sistem ustvari ločene strukture seznamov za shranjevanje njihovih deskriptorjev. Organizacija teh seznamov je odvisna od načel, ki so podlaga za razporejanje niti za dani OS.

Namen razporejanja niti je povsem očiten - določanje vrstnega reda izvajanja niti v pogojih zunanje ali notranje večopravilnosti. Kako doseči ta cilj pa je močno odvisno od vrste OS. Najprej si oglejmo načela razporejanja za operacijske sisteme za splošne namene. Za takšne operacijske sisteme je nemogoče vnaprej predvideti, koliko in katere niti se bodo izvajale v danem trenutku in v kakšnih stanjih bodo. Zato mora načrtovanje potekati dinamično na podlagi zbiranja in analize informacij o trenutnem stanju računalniškega sistema.

Za to OS vključuje modul razporejevalnika, ki izvaja izbrane algoritme razporejanja. Ker je ta modul programska koda, mora razporejevalnik za nekaj časa prevzeti CPE, da lahko izvaja svoje naloge. Iz tega sledi, da morajo biti algoritmi za razporejanje čim bolj enostavni, sicer obstaja nevarnost, da bo sistem za reševanje notranjih problemov porabil nedopustno veliko časa, za izvajanje aplikacijskih programov pa bo zmanjkalo časa.

Poleg računske preprostosti bi morali algoritmi načrtovanja imeti naslednje splošne lastnosti:

  • zagotavljanje največje možne obremenitve procesorja;
  • zagotavljanje enakomerne obremenitve virov računalniškega sistema;
  • zagotavljanje poštenih storitev za vse procese in niti;
  • zmanjšanje odzivnega časa za interaktivne procese.
Med obstojem OS je bilo predlaganih in implementiranih več načel upravljanja niti. Trenutno večina univerzalnih operacijskih sistemov uporablja preventivno večopravilno metodo, ki ima tudi več različic. Metoda temelji na dveh pomembnih in dokaj razumljivih načelih: rezanje časa procesorja in prioritete niti.

Kvantizacija pomeni, da sistem vsaki niti dodeli določen časovni interval (kvant), v katerem lahko procesor potencialno izvede kodo te niti. Po izteku dodeljenega kvantuma planer prisilno preklopi procesor na izvajanje druge pripravljene niti (če seveda obstaja), s čimer staro aktivno nit postavi v stanje pripravljenosti. To zagotavlja, da nobena posamezna nit ne obremenjuje CPE-ja predolgo (kot je bilo v prejšnjih sistemih s tako imenovano nepreventivno ali kooperativno večopravilnostjo). Seveda dodeljena kvantna nit morda ne bo v celoti izkoriščena, če se med izvajanjem prekine normalno ali nenormalno, ali zahteva pojav nekega dogodka ali jo sistem prekine.

Za učinkovito delovanje OS je izbira kvantne vrednosti velikega pomena. Zelo majhne kvantne vrednosti povzročijo pogoste preklope CPE, kar poveča stroške zaradi potrebe po nenehnem vzdrževanju konteksta prekinljive niti in nalaganju konteksta prebuljive niti. Ravno nasprotno, velike kvantne vrednosti zmanjšajo iluzijo hkratnega izvajanja več aplikacij. Nekateri načrtovalci lahko spreminjajo količine v določenih mejah in jih povečajo za tiste niti, ki ne izkoristijo v celoti dodeljenega časa, na primer zaradi pogostih klicev V/I operacij. Tipičen razpon kvantne spremembe je od 10 do 50 milisekund. V tem primeru je treba upoštevati vedno večje hitrosti delovanja sodobnih procesorjev: v 10 milisekundah (torej v 1/100 sekunde) bo procesor imel čas za izvedbo približno 10 milijonov elementarnih ukazov.

Kvantno vrednost lahko povežete s prednostjo niti. Prednost določa pomembnost niti in vpliva na to, kako pogosto se nit izvaja in morda na količino dodeljenega kvantuma. Intuitivno je jasno, da imajo niti lahko različne stopnje pomembnosti: sistemske niti - višje (sicer OS ne bo mogel rešiti svojih nalog), niti aplikacij - manj visoke. Mnogi operacijski sistemi vam omogočajo združevanje niti glede na njihovo pomembnost, pri čemer ločite tri skupine ali razrede:

  • niti v realnem času z najvišjo stopnjo prioritete;
  • sistemske niti z nižjo stopnjo prioritete;
  • niti aplikacije z najnižjo prioriteto.
Znotraj vsake skupine je dodeljen lasten obseg možnih prioritetnih vrednosti in ti obsegi se ne sekajo, tj. največja možna prioriteta aplikacijske niti bo vedno strogo nižja od najmanjše možne prioritete sistemskih niti. Znotraj vsake skupine je mogoče uporabiti različne algoritme za upravljanje prioritet.

Če lahko sistem spremeni prioriteto niti, se takšne prioritete imenujejo dinamične, drugače - fiksne. Seveda je veliko lažje implementirati fiksne prioritete, medtem ko dinamične prioritete omogočajo pravičnejšo porazdelitev procesorskega časa. Na primer, niti, ki intenzivno uporabljajo zunanje naprave, zelo pogosto blokirajo, dokler se dodeljena časovna rezina ne zaključi, tj. teh kvantov ne uporabite v celoti. Pri deblokadi takih niti je pošteno dati višjo prioriteto za hitro aktivacijo, kar zagotavlja večjo obremenitev relativno počasnih zunanjih naprav. Po drugi strani pa lahko sistem, če nit popolnoma porabi svoj dodeljeni kvantum, zmanjša njeno prioriteto, potem ko jo prekine. Tako imajo višje prioritete krajše niti, ki hitro sprostijo procesor, posledično pa se doseže bolj enakomerna obremenitev računalniškega sistema kot celote.

Precej zanimiva in pogosto uporabljena vrsta prioritete je tako imenovana absolutna prioriteta: takoj ko se med pripravljenimi nitmi pojavi nit, katere prioriteta je višja od prioritete trenutne aktivne niti, se ta aktivna nit prekine pred urnik in procesor se prenese v nit z višjo prioriteto.

Za izvajanje prednostnega servisiranja mora OS ustvariti in vzdrževati nabor prednostnih čakalnih vrst. Za vsako možno prednostno vrednost se ustvari lastna čakalna vrsta, v katero so niti (v obliki njihovih deskriptorjev) postavljene strogo v skladu z vrstnim redom. Razporejevalnik pregleda te čakalne vrste v prednostnem vrstnem redu in za izvedbo izbere prvo nit v neprazni čakalni vrsti z najvišjo prioriteto. Iz tega sledi, da se bodo niti z nižjimi prioritetami izvajale samo, če so vse čakalne vrste z višjimi prioritetami prazne. Če je sprememba prioritete dovoljena, mora biti razporejevalnik sposoben premakniti nit v drugo čakalno vrsto glede na novo prednostno vrednost.

Matrika prednostnih čakalnih vrst je shematično predstavljena na naslednji sliki, kjer so zaradi priročnosti niti z višjo prioriteto zbrane na levi strani matrike, nižje prioritete na desni, same prioritete pa se spreminjajo od 1 (največja) do n. (najmanj). Simbol "nit i.2" označuje, da ima ta nit prednost i in je druga po vrstnem redu v čakalni vrsti.

Za spremembo prioritete in po možnosti časovnega kvantuma potrebuje planer naslednje podatke: osnovno vrednost prioritete in kvantuma, čas čakanja v čakalni vrsti, akumulirani čas izvajanja, intenzivnost dostopa do I/O operacij. Vse te informacije morajo biti shranjene v ustreznih podatkovnih strukturah.

Posledično razporejevalnik začne delovati, ko se zgodi eden od naslednjih dogodkov:

  • zaključek časovne rezine za trenutno aktivno nit (signal iz sistemskega časovnika);
  • normalno dokončanje kode trenutne aktivne niti;
  • Nenormalna prekinitev kode trenutne aktivne niti;
  • zahteva aktivne niti za zaseden sistemski vir;
  • pojav niti z višjo prioriteto med pripravljenimi nitmi.
To zažene kodo razporejevalnika, ki pregleda prednostne čakalne vrste in izbere nit z najvišjo prednostjo. Po tem pride do dejanskega preklopa niti:
  • oblikuje se kontekst prekinjene niti;
  • z uporabo konteksta na novo aktivirane niti se obnovi potrebno stanje računalniškega sistema, zlasti se potrebne vrednosti naložijo v vse registre procesorja;
  • Ker se naslov naslednjega ukaza aktivirane niti, ki naj se izvede, vnese v register programskega števca iz konteksta, procesor nadaljuje z izvajanjem kode nove niti točno od točke, kjer je bila prekinjena.
Razporejanje niti v sistemih v realnem času temelji na različnih načelih. Ker je za takšne sisteme najpomembnejši kazalnik hitrost delovanja, se načrtovanje izvaja statično. Za to je vnaprej zgrajena tako imenovana preklopna tabela, s pomočjo katere se glede na trenutno stanje računalniškega procesa hitro in nedvoumno določi trenutno delujoča nit.

  • Prevajanje
  • Vadnica

Od prevajalca: ta članek je sedmi v seriji prevodov uradnega vodnika po knjižnici SFML. Najdete lahko prejšnji članek. Cilj te serije člankov je ljudem, ki ne poznajo izvirnega jezika, omogočiti, da se seznanijo s to knjižnico. SFML je preprosta večplatformska multimedijska knjižnica. SFML ponuja preprost vmesnik za razvoj iger in drugih multimedijskih aplikacij. Izvirni članek najdete. Začnimo.

Kaj je tok?

Večina od vas že ve, kaj je tok, a razložimo, kaj je to za tiste, ki se ne spoznajo na to temo.

Nit je v bistvu zaporedje navodil, ki se izvajajo vzporedno z drugimi nitmi. Vsak program ustvari vsaj eno nit: glavno nit, ki izvaja funkcijo main(). Program, ki uporablja samo glavno nit, je enoniten; če dodate eno ali več niti, postane večniten.

Torej, na kratko, niti so način za opravljanje več stvari hkrati. To je lahko uporabno na primer za prikazovanje animacij in obdelavo uporabniškega vnosa med nalaganjem slik ali zvokov. Niti se pogosto uporabljajo tudi v omrežnem programiranju; med čakanjem na prejem podatkov se bo aplikacija še naprej posodabljala in risala.

Niti SFML ali std::thread?

Standardna knjižnica C++ v svoji zadnji različici (2011) ponuja niz razredov za delo z nitmi. V času pisanja SFML standard C++11 še ni bil napisan in ni bilo standardnega načina za ustvarjanje niti. Ko je bil izdan SFML 2.0, je bilo veliko prevajalnikov, ki tega novega standarda niso podpirali.

Če delate s prevajalnikom, ki podpira novi standard in vsebuje datoteko glave, pozabite na razrede toka SFML in namesto tega uporabite standardne razrede C++. Toda če delate z nestandardnim prevajalnikom ali nameravate distribuirati svojo kodo in želite popolno prenosljivost, so razredi toka SFML dobra izbira

Ustvarjanje tokov s SFML

Dovolj tarnanja, poglejmo kodo. Razred, ki vam omogoča ustvarjanje niti z uporabo SFML, se imenuje sf::Thread in takole izgleda v akciji:

#vključi #vključi void func() ( // ta funkcija se zažene, ko se pokliče thread.launch() za (int i = 0; i< 10; ++i) std::cout << "I"m thread number one" << std::endl; } int main() { // создание потока с функцией func в качестве точки входа sf::Thread thread(&func); // запуск потока thread.launch(); // главные поток продолжает быть запущенным... for (int i = 0; i < 10; ++i) std::cout << "I"m the main thread" << std::endl; return 0; }
V tej kodi se glavni in func funkciji izvajata vzporedno po klicu thread.launch(). Posledica tega je, da je izhod besedila iz obeh funkcij v konzoli mešan.

Vstopna točka v tok, tj. funkcija, ki bo izvedena ob zagonu niti, mora biti posredovana konstruktorju sf::Thread. sf::Thread poskuša biti prilagodljiv in sprejemati različne vstopne točke: nečlanske funkcije ali metode razreda, funkcije z ali brez argumentov, funktorje itd. Zgornji primer prikazuje, kako uporabljati funkcijo člana, tukaj je nekaj drugih primerov.

  • nečlanska funkcija z enim argumentom:

    Void func(int x) ( ) sf::Thread thread(&func, 5);

  • metoda razreda:

    Razred MyClass (javno: void func() ( )); objekt MyClass; sf::Thread thread(&MyClass::func, &object);

  • funktor (funkcijski objekt):

    Struct MyFunctor ( void operator()() ( )); sf::Thread thread(MyFunctor());

Zadnji primer, ki uporablja funktor, je najmočnejši, ker lahko sprejme katero koli vrsto funktorja in zato naredi razred sf::Thread združljiv s številnimi vrstami funkcij, ki niso neposredno podprte. Ta funkcija je še posebej zanimiva pri lambda izrazih C++11 ali std::bind.

// z lambda funkcijo sf::Thread thread(())( std::cout<< "I am in thread!" << std::endl; });
// s std::bind void func(std::string, int, double) ( ) sf::Thread thread(std::bind(&func, "hello", 24, 0.5));
Če želite uporabiti sf::Thread znotraj razreda, ne pozabite, da nima standardnega konstruktorja. Zato ga morate inicializirati v konstruktorju svojega razreda na inicializacijskem seznamu:

Razred ClassWithThread (javno: ClassWithThread() : m_thread(&ClassWithThread::f, to) ( ) zasebno: void f() ( ... ) sf::Thread m_thread; );
Če res morate instancirati sf::Thread po inicializaciji predmeta, ga lahko instancirate na kupu.

Začetek niti

Ko ustvarite primerek sf::Thread, ga morate zagnati s funkcijo run.

Sf::Thread thread(&func); thread.launch();
launch pokliče funkcijo, ki ste jo posredovali konstruktorju nove niti, in se takoj zapre, tako da lahko klicajoča nit takoj nadaljuje z izvajanjem.

Ustavljanje niti

Nit se samodejno prekine, ko funkcija, ki služi kot vstopna točka niti, vrne njeno vrednost. Če želite počakati na dokončanje niti iz druge niti, lahko pokličete njeno funkcijo čakanja.

Sf::Thread thread(&func); // zagon niti thread.launch(); ... // izvajanje se blokira, dokler se nit ne prekine thread.wait();
Funkcijo čakanja implicitno pokliče tudi destruktor sf::Thread, tako da nit ne more ostati v teku (in nenadzorovana), potem ko je njen primerek sf::Thread uničen. Zapomnite si to, ko upravljate svoje niti (glejte zadnji del članka).

Zaustavitev niti

V SFML ni funkcije, ki bi omogočala zaustavitev niti; edini način za zaustavitev niti je, da to storite znotraj kode same niti. Z drugimi besedami, začasno ustavite lahko samo trenutno nit. Če želite to narediti, lahko pokličete funkcijo sf::sleep:

Void func() ( ... sf::sleep(sf::milliseconds(10)); ... )
sf::sleep ima en argument - čas spanja. Ta čas je mogoče izraziti v kateri koli enoti, kot je prikazano v članku o.

Upoštevajte, da lahko s to funkcijo prekinete katero koli nit, tudi glavno nit.

Sf::sleep je najučinkovitejši način za prekinitev niti: medtem ko je nit začasno ustavljena, (nit) ne porabi skoraj nobenih virov procesorja. Aktivna napetost, ki temelji na čakanju, kot prazna zanka while, porabi 100 % CPE in naredi ... nič. Vendar ne pozabite, da je dolžina vzmetenja le vodilo; Dejansko trajanje začasne zaustavitve (več ali manj od časa, ki ga določite) je odvisno od OS. Zato se ne zanašajte na to funkcijo za zelo natančno merjenje časa.

Zaščita skupnih podatkov

Vse niti v programu si delijo nekaj pomnilnika, imajo dostop do vseh spremenljivk v svojem obsegu. To je zelo priročno, a tudi nevarno: od trenutka, ko se nit vzporedno zažene, lahko različne niti uporabljajo spremenljivke ali funkcije hkrati. Če operacija ni varna za niti, lahko povzroči nedefinirano vedenje (tj. lahko se zruši ali povzroči poškodbo podatkov).

Obstaja več programskih orodij, ki vam lahko pomagajo zaščititi podatke v skupni rabi in narediti vašo nit kode varno, ta se imenujejo sinhronizacijski primitivi. Najpogostejši primitivi so muteksi, semaforji, pogojne spremenljivke in spinlocki. Vse so različice istega koncepta: zaščitijo del kode tako, da samo določeni niti dajo pravico do dostopa do podatkov in blokirajo druge.

Najpogostejši (in uporabljen) primitiv je mutex. Mutex pomeni medsebojna izključitev. To je zagotovilo, da lahko samo ena nit izvede kodo. Oglejmo si, kako delujejo muteksi na spodnjem primeru:

#vključi #vključi sf::Mutex mutex; void func() (mutex.lock(); for (int i = 0; i< 10; ++i) std::cout << "I"m thread number one" << std::endl; mutex.unlock(); } int main() { sf::Thread thread(&func); thread.launch(); mutex.lock(); for (int i = 0; i < 10; ++i) std::cout << "I"m the main thread" << std::endl; mutex.unlock(); return 0; }
Ta koda uporablja skupni vir (std::cout) in, kot lahko vidimo, to vodi do nezaželenih rezultatov. Izhod toka se meša v konzoli. Da bi zagotovili, da se izhod pravilno natisne, namesto da bi bil pomešan, zaščitimo ustrezna področja kode z mutexom.

Prva nit, ki doseže klic mutex.lock(), zaklene mutex in dobi dostop do kode, ki natisne besedilo. Ko druge niti dosežejo klic mutex.lock(), je mutex že zaklenjen in druge niti prekinejo svoje izvajanje (to je podobno klicu sf::sleep, speča nit ne porablja časa procesorja). Ko prva nit odklene mutex, druga nit nadaljuje njegovo izvajanje, zaklene mutex in natisne besedilo. To povzroči, da se besedilo v konzoli natisne zaporedno in ni pomešano.

Mutex ni samo primitiv, ki ga lahko uporabite za zaščito podatkov v skupni rabi, lahko ga uporabite v številnih drugih primerih. Če pa vaša aplikacija dela zapletene stvari pri delu z nitmi in menite, da zmožnosti muteksov niso dovolj, poiščite drugo knjižnico, ki ima več funkcionalnosti.

Mutex zaščita

Ne skrbite: muteksi so že varni za niti, zato jih ni treba zaščititi. Vendar niso izjemoma varni. Kaj se zgodi, če se sproži izjema, medtem ko je mutex zaklenjen? Nikoli ga ni mogoče odkleniti in bo ostal zaklenjen za vedno. Vse niti, ki poskušajo odkleniti zaklenjeni mutex, bodo za vedno blokirane. V nekaterih primerih bo vaša prijava zamrznjena.

Za zagotovitev, da je mutex vedno odklenjen v okolju, v katerem lahko sproži izjemo, SFML zagotavlja razred RAII, ki vam omogoča, da mutex zavijete v razred sf::Lock. Zaklepanje se pojavi v konstruktorju, odklepanje pa v destruktorju. Enostavno in učinkovito.

Sf::Mutex mutex; void func() ( sf::Lock lock(mutex); // mutex.lock() functionThatMightThrowAnException(); // mutex.unlock() če funkcija sproži izjemo) // mutex.unlock()
Ne pozabite, da je sf::Lock mogoče uporabiti tudi v funkcijah, ki imajo več vrnjenih vrednosti.

Sf::Mutex mutex; bool func() ( sf::Lock lock(mutex); // mutex.lock() if (!image1.loadFromFile("...")) return false; // mutex.unlock() if (!image2. loadFromFile("...")) vrne false; // mutex.unlock() če (!image3.loadFromFile("...")) vrne false; // mutex.unlock() vrne true; ) // mutex .unlock()

Pogoste napačne predstave

Nekaj, kar se pogosto spregleda: nit ne more obstajati brez ustreznega primerka
 
Članki Avtor: tema:
Popravilo bliskovnega pogona USB naredi sam: odpravljanje težav s strojno in programsko opremo
Pozdravljeni, dragi prijatelji! Obstaja več razlogov, zakaj lahko naletite na dejstvo, da računalnik ne vidi bliskovnega pogona. Ta težava se lahko pojavi v katerem koli OS. Pojavi se v sistemih Windows XP in Windows 10. Če računalnik ne prepozna
Računalnik ne vidi bliskovnega pogona, kaj naj storim?
Zdaj skoraj vsi uporabljajo bliskovne pogone USB. To je preprost in zanesljiv način za prenos in shranjevanje informacij. Toda okvara teh naprav je postala pogosta težava mnogih uporabnikov. Spodaj so vsi možni vzroki težav in var
Kako popolnoma očistiti računalnik
Na žalost nepazljivost do zmogljivosti osebnega računalnika v večini primerov zmanjša na nič, kar seveda vpliva na zmogljivost in funkcionalnost naprave. Kakovost dela in pravilna izvedba vseh procesov
Prijavite se na mojo stran v socialnem omrežju “Photostrana”
Ta publikacija bo posvečena najbolj priljubljeni storitvi za zmenke Photostrana: moja stran, kako se prijaviti brez gesla in ali je resnična? To je veliko zabavno socialno omrežje, ki omogoča dostop do uporabniških profilov za iskanje partnerja. Oglejmo si podrobneje f