# Co to jsou procesy a prováděcí toky

V době, kdy jednotliví uživatelé počítačů přestali být závislí na centrálních výpočetních střediscích a sami usedali k terminálům unixových minipočítačů, téměř nebylo možno bez podrobné znalosti pojmu proces s počítačem pracovat. Na druhé straně dnes naprostá většina uživatelů vůbec netuší, že po kliknutí na ikonu spouštějící jejich oblíbený program operační systém vytvoří proces tento program vykonávající.

Pokud ale potřebujete vyladit prostředí operačního systému aby vaši aplikaci provozoval bez zbytečných zaváhání, pojmům proces a prováděcí tok se nevyhnete.

## Procesy

Aby moderní operační systém mohl efektivně využívat technického vybavení počítače a současně aby rychle interagoval s uživatelem a plnil jeho příkazy, je nezbytné, aby dokázal spouštět více procesů (vykonávat několik programů) najednou. To na jediném procesoru samozřejmě není možné, proto operační systém využívá tzv. časového sdílení. Časové sdílení znamená, že po určitém čase běhu procesu (zvaném časové kvantum) operační systém uschová stav procesu (registry procesoru, adresáře stránek virtuální paměti apod.) a vyvolá stav jiného procesu, který pokračuje v běhu. Maximální doba běhu jednoho procesu (délka časového kvanta) není pevně stanovena a v různých systémech se může lišit. V současné době to je u operačních systémů rodiny Windows`NT asi 15 ms pro procesy na pozadí a 45 ms pro proces probíhající na popředí, tedy právě interagující s uživatelem. Systémy Windows`9x neprodlužují časové kvantum procesů na popředí, namísto toho jim zvyšují prioritu.

Jednotlivé procesy jsou jen málokdy programovány tak, že trvale provádějí nějaký výpočet (to je typické spíše pro vědecko-technické výpočty). Většinou interagují z uživatelem a jejich činnost je tak řízena řadou podmínek. Často proces čeká na akci uživatele -- pohyb myši nebo stisk klávesy. Příčin pozastavení procesu je ovšem podstatně více. Procesy čekají na přečtení dat z disku, na příjem nebo odeslání paketu dat po síti apod. Velice často více procesů spolupracuje na jediném cíli a proto navzájem synchronizují svoji činnost. Využívají k tomu neobyčejně bohaté nabídky speciálních objektů rozhraní Win32, jako jsou Události, Semafory, Mutexy apod. Je zcela běžné pozastavit proces např. čekáním až jiný proces signalizuje nějakou událost. Rovněž lze čekat na ukončení běhu nějakého procesu. Co se stane s časovými kvanty? Operační systém samozřejmě ví, který proces je připraven běžet a který čeká a po odebrání procesoru jednomu procesu vybere jen proces připravený k běhu, který na nic nečeká. Procesy tedy čekají pasivně, uspány, a nevykonávají žádný kód. Čekání procesů je tedy z hlediska spotřeby času procesoru velmi levné a efektivní. Pokud neexistuje žádný jiný proces připravený k běhu, operační systém vrátí vykonávání přerušenému procesu. A pokud se i tento proces uspí, každý operační systém má v zásobě jeden speciální proces nazvaný "idle process", který nic nedělá, protože běh počítače není možné prostě jen zastavit, počítač musí pracovat i když nepracuje.

Protože v operačním systému pracuje více procesů různé důležitosti, je nutné použít mechanizmu priorit, který při výběru dalšího procesu dokáže upřednostnit jeden proces před druhým. Priority bývají v různých systémech implementovány různě, například z priority může být odvozena délka časového kvanta přiděleného danému procesu. Procesy s vyšší prioritou tak pracují vždy delší dobu než procesy s nižší prioritou. Přístup rozhraní Win32 k prioritám je mnohem důslednější -- pokud existuje proces s vyšší prioritou připravený k běhu, žádný proces s nižší prioritou se nedostane ke slovu. Na první pohled to vypadá jako nefunkční mechanizmus -- běžící proces s vyšší prioritou zablokuje vše ostatní. Ve skutečnosti ale tento mechnismus přináší lepší predikovatelnost chování celého systému a zlepšuje jeho odezvu. Problém s nepřetržitě běžícím procesem vysoké priority blokujícím ostatní procesy se řeší jednoduše -- takto navržená aplikace je chybná aplikace a nepoužívá se. Procesy vysoké priority jsou probuzeny po vzniku patřičné události, ve zlomku časového kvanta provedou svou činnost a opět se uspí, uvolní místo procesům s menší prioritou.

Pokud nějaký proces potřebuje pracovat nepřetržitě, má na vybranou v podstatě ze dvou priorit -- standardní priority a nejnižší priority. Pokud má nejnižší prioritu, bude využívat skutečně jen dobu, po kterou by počítač prázdně čekal (pracoval by "idle proces" při neexistenci žádného procesu připraveného k běhu. Běžné aplikace budou pracovat na plný výkon. Pokud nepřetržitě pracující proces bude mít standardní prioritu, bude se s běžnými aplikacemi dělit o čas a citelně zvýší reakční dobu těchto aplikací.

Druhou vlastností operačního systému je naprostá izolace jednotlivých procesů. Tato izolace je nutná kvůli zajištění bezpečnosti -- jeden proces (alespoň teoreticky) nesmí ovlivnit běh ostatních procesů a operačního systému, nesmí zasahovat do paměti spravované jinými procesy a nesmí tuto paměť ani číst. Zkrátka každý proces musí mít vytvořeno takové prostředí, jako by na počítači pracoval sám. Toto je možné jen s přispěním hardware -- procesoru počítače. Prakticky všechny moderní procesory mají zabudovány mechanizmy vytváření tzv. virtuální paměti. To znamená, že adresový prostor 0 až 4`GB využívaný procesem není přímo mapován do fyzické paměti počítače, ale je po tzv. stránkách rozdělen po fyzické paměti zcela nespojitě a prokládaně se stránkami paměti jiných procesů. Hardware zajišťuje překlad mezi virtuální adresou, jak ji vidí proces, a skutečnou adresou pomocí stránkových adresářů, které spravuje operační systém.

Významným důsledkem virtualizace paměťového prostoru je možnost využívat více paměti, než je fyzicky v počítači přítomno. O stránkách (blocích) paměti existují pouze záznamy ve stránkových adresářích a není nezbytně nutné, zby byly přítomny ve fyzické paměti. Namísto toho se mohou vyskytovat na disku. Stránky kódu představující programy jsou přítomny v samotných spustitelných souborech (typu '.EXE' a '.DLL'), stránky představující datové bloky ve speciálním odkládacím souboru (tzv. "swap file"). Pokud proces přistoupí do části paměti, která je ve stránkovém adresáři označena jako nepřítomná, procesor přeruší vykonávání programu a vyvolá podprogram pro ošetření této výjimky, který je součástí operačního systému. Tento podprogram nalezne volné místo v paměti (tzv. stránkový rámec) a chybějící stránku do tohoto místa zavede z patřičného souboru na disku. Poté pokračuje vykonávání procesu od instrukce přistupující k paměti. Celá akce výměny stránky je provedena skrytě a uživatelský proces ji vůbec nezaznamená. Nalézt volný stránkový rámec samozřejmě nemusí být vůbec jednoduché a může si vyžádat odložení jiné stránky na disk. Výhodnější je uvolnit stránkový rámec zabraný kódem než daty, neboť kód se zpravidla nemění a lze jej prostě z paměti odstranit a v případě potřeby opět nahrát ze spustitelného souboru. Stejné je to se stránkami obsahujícími data, která nebyla změněna (zápis do stránky je také zaznamenán v položce stránkového adresáře). Datovou stránku se změněnými daty je ale třeba nejprve uložit do odkládacího souboru.

Pro proces je tedy charakteristické:

- Proces představuje vykonávání nějakého programu.
- Procesů zpravidla existuje více najednou. Vykonávány jsou prokládaně po časových kvantech. Jen málo procesů pracuje nepřetržitě. Většinou jsou pozastavovány, když čekají na akci uživatele, na vstupně/výstupní operaci, na časový okamžik nebo na synchronizaci s jiným procesem.
- Procesy mají přiděleny priority. Existuje-li proces s vyšší prioritou, má vždy přednost před procesy s nižší prioritou.
- Instrukce programu přistupují k paměti počínaje adresou 0 a konče vrcholem paměti 4 GB. Tyto adresy ale nepředstavují skutečné adresy fyzické paměti, jsou mechanizmem stránkování překládány.
- Procesy mohou alokovat více paměti, než je v počítači fyzicky přítomno. Operační systém paměť mechanizmem virtualizace vyměňuje mezi fyzickou pamětí a diskovými soubory.
- Jednotlivé procesy si navzájem nevidí do paměti, do souborů nebo komunikačních kanálů. Sdílení dat je možné jen speciálními funkcemi API, které zajistí bezpečnost.

## Prováděcí toky

Již víte, že operační systém při různých příležitostech přepíná kontext z jednoho procesu na druhý. Takové přepnutí kontextu je náročná a relativně pomalá akce čítající až tisíce instrukcí. Navíc je to akce čistě režijní, pouze ubírající výkon procesoru aplikacím. Hlavní tíha přepínání není ani tak v rychlé výměně obsahu registrů, ale v nutnosti zajistit virtuální adresový prostor pro každý proces pomocí zvláštních stránkových adresářů, prostor pro popisovače souborů a jiných objektů apod. Dále je nutno zajistit změnu popisovačů oprávnění přístupu k různým prostředkům, neboť jiný proces mohl spustit uživatel s úplně jinými přístupovými právy.

Přitom mnohdy je na obtíž i samotná vzájemná izolace procesů. Serverová aplikace například může vytvářet samostatný proces pro každý zpracovávaný požadavek a přitom potřebuje přistupovat do společné oblasti paměti, což u procesů není jednoduché.

Proto vznikl mimo proces ještě nový mechanizmus anglicky nazývaný "thread", což česky znamená vlákno nebo nit. V češtině se vžilo označení "prováděcí tok". Podstata prováděcích toků je podobná jako podstata procesů, jedná se o jejich odlehčenou variantu. Prováděcí toky se taktéž přepínají po určitých časových kvantech, taktéž mají priority a taktéž mohou čekat na rozličné události. Jedinou výjimkou je, že každý prováděcí tok existuje jako součást nějakého procesu a využívá jeho adresový prostor (tedy jeho stránkové adresáře), jeho popisovače souborů a systémových objektů apod. To znamená, že pokud prováděcí toky patří jednomu procesu, vzájemně vidí na všechny objekty (proměnné) v paměti a mohou na ně přistupovat. Totéž samozřejmě platí i o souborech a vůbec všech prostředcích procesu.

Při přepnutí kontextu z jednoho prováděcího toku na jiný tok stejného procesu operační systém ušetří spoustu práce, neboť prakticky jen vymění registry procesoru a pokračuje ve vykonávání. Je tedy možné tvořit aplikaci jako skupinu paralelně provádějících se toků, které sdílejí společná data a na jejichž přepínání spotřebuje operační systém relativně málo času. Jen pokud je měněn kontext na prováděcí tok jiného procesu, je režie přepnutí vyšší.

Jak je to tedy s procesy a prováděcími toky? Mezi čím se vlastně přepíná? Starší systémy, navržené ještě před rozšířením konceptu prováděcích toků a o možnost tvorby prováděcích toků dodatečně rozšířené, mezi oběma pojmy rozlišují jen málo. Nový prováděcí tok využívá všech mechanizmů procesů, jen je poznamenáno, že při přepnutí na jiný proces se shodným kódem není potřeba měnit stránkové adresáře a tabulky popisovačů souborů.

V prostředí Win32 je přístup k prováděcím tokům mnohem radikálnější. API Win32 bylo od počátku navrhováno pro podporu více prováděcích toků v jednom procesu a základní vykonavatelnou jednotkou ve Win32 tedy na rozdíl od jiných systémů není proces, ale prováděcí tok. V podstatě vše, co bylo řečeno o vykonávání procesů, jejich prioritách a přepínání je ve skutečnosti potřeba vztáhnout na prováděcí toky. I pokud aplikace není konstruována s využitím více prováděcích toků, její spuštění v prostředí Win32 způsobí, že mimo vytvoření objektu třídy proces pro danou aplikaci se vždy vytvoří alespoň jeden objekt typu prováděcí tok zajišťující vykonávání kódu aplikace.

## Priority procesů a prováděcích toků

API Win32 nedovoluje nastavit prioritu prováděcímu toku na konkrétní hodnotu. Ačkoliv v dnešních implementacích Win32 existuje 32 úrovní priorit, prováděcí toky toto číslo nenastavují explicitně. Namísto toho každý prováděcí tok může určit svou relativní prioritu vůči tzv. třídě priority procesu. Třída priority procesu pak určuje, jakou konkrétní hodnotu priority budou mít prováděcí toky danému procesu náležející.

Win32 definuje 4 třídy priorit procesů:

čekací (IDLE_PRIORITY_CLASS) úroveň priority 4 normální (NORMAL_PRIORITY_CLASS) úroveň priority 8 vysoká (HIGH_PRIORITY_CLASS) úroveň priority 13 realtime (REALTIME_PRIORITY_CLASS) úroveň priority 24

Prováděcí toky pak určují svou prioritu relativně od třídy priority procesu v 7 stupních:

THREAD_PRIORITY_IDLE THREAD_PRIORITY_LOWEST THREAD_PRIORITY_BELOW_NORMAL THREAD_PRIORITY_NORMAL THREAD_PRIORITY_ABOVE_NORMAL THREAD_PRIORITY_HIGHEST THREAD_PRIORITY_TIME_CRITICAL

Skutečné číselné priority prováděcích toků, rozhodující o tom, který připravený prováděcí tok bude upřednostněn a který bude blokován jsou určováy podle následující tabulky:

    Relativní priorita toku        Třída priority procesu
                                   IDLE   NORMAL   HIGH  REALTIME
    THREAD_PRIORITY_IDLE             1       1       1      16
    THREAD_PRIORITY_LOWEST           2       6      11      22
    THREAD_PRIORITY_BELOW_NORMAL     3       7      12      23
    THREAD_PRIORITY_NORMAL           4       8      13      24
    THREAD_PRIORITY_ABOVE_NORMAL     5       9      14      25
    THREAD_PRIORITY_HIGHEST          6      10      15      26
    THREAD_PRIORITY_TIME_CRITICAL   15      15      15      31

I když toto přiřazení není součástí definice Win32 API a firma Microsoft si vyhrazuje právo konkrétní hodnoty v budoucnu měnit, stojí za povšimnutí výsadní postavení procesů s třídou priority REALTIME. Všechny prováděcí toky takového procesu mají vyšší prioritu, než všechny prováděcí toky jakékoliv jiné třídy procesu. Tato třída je vyhrazena pro velmi pečlivě programované systémové procesy, neboť priorita je natolik vysoká, že by prováděcí tok mohl zablokovat i základní operace ovladačů pevných disků apod.

Většina systémů Windows je určena jako klientské stanice a tak operační systém provádí řadu akcí, aby zlepšil uživatelský dojem z rychlosti odezvy:

- Prováděcí toky procesu na popředí (procesu vlastnící okno, jež přijímá vstupy z klávesnice) jsou systematicky zvýhodňovány před jinými prováděcími toky. Způsob tohoto zvýhodnění je ale odlišný u Windows`9x a u Windows`NT:

- Windows`9x zvýší prioritu prováděcích toků procesu na popředí o jedničku.
- Windows`NT prodlouží časové kvantum prováděcích toků procesu na popředí na trojnásobek standardního časového kvanta.

- Prováděcímu toku, který přijímá událost od uživatele (pohyb myši, stisk tlačítka klávesnice) systém zvýší prioritu o dva stupně pro první časové kvantum po příjmu uživatelské události a o jeden stupeň pro následující časové kvantum. Tím se sníží pravděpodobnost, že proces komunikující s uživatelem bude odstaven jiným procesem se stejnou prioritou.

Protože Windows`NT jsou určeny i jako serverový operační systém, kdy prioritou je odezva systému na podněty přijímané prostřednictvím sítě procesy na pozadí, je v tomto systému možné upřednostňování procesů na popředí zcela potlačit.

Není možné v rámci této dokumentace zcela pokrýt rozsáhlou problematiku procesů a prováděcích toků v operačních systémech. Podrobně je tato problematika popsána v celé řadě knih, např. Jeffrey Richter: Windows pro pokročilé a experty, Computer Press 1997 a Windows`NT Workstation Resource Kit, Computer Press 1996.