Vyšlo v týdeníku Computerworld č. 13/95 v roce 1995
Vytištěno z adresy: http://www.earchiv.cz/a95/a513c120.php3

Thread

Není nad to, když se věci mohou dělat současně. To samozřejmě platí i pro počítače. Většina těch dnešních však není příliš uzpůsobena myšlence paralelismu, a souběžnému provádění více různých činností nevychází zrovna vstříc. Příčinou je již samotná koncepce drtivé většiny dnešních počítačů, která vychází z myšlenek pana von Neumanna, formulovaných v době kolem druhé světové války. Počítače, postavené na základě těchto myšlenek (tj. počítače s tzv. von Neumannovou architekturou), jsou v zásadě sekvenční, a počítají jen s jediným „hlavním" výpočtem, probíhajícím postupně, neboli sekvenčně, na jediném procesoru.

Pokud někdo na takovémto počítači chce dosáhnout alespoň zdání paralelismu, neboli souběžného provádění více různých výpočtů - například odpovídajících různým úlohám téhož uživatele či úlohám různých uživatelů - musí si sám zajistit vše potřebné. Tedy implementovat takové mechanismy, které zprostředkují alespoň rychlé střídání více různých výpočtů na jediném dostupném procesoru. Typicky jsou tyto prostředky realizovány jako součást operačního systému, který tak vytváří potřebné víceúlohové prostředí.

Jak ale vůbec řešit střídání jednotlivých výpočtů na jediném procesoru? Na co je třeba dávat největší pozor?

Nejspíše na to, aby vzájemné střídání konkrétních výpočtů bylo plně transparentní. Neboli aby každý jednotlivý výpočet vůbec nemusel vědět o tom, že se o procesor dělí i s jinými výpočty formou střídání. Každý jednotlivý proces by naopak měl právo si myslet, že je na světě sám, a že má procesor výhradně k vlastní dispozici. Jak mu ale zachovat tuto iluzi, když ve skutečnosti je každý výpočet čas od času odstaven od svého procesoru, a ke slovu se dostává jiný proces?

Podstatné je v tomto ohledu zajistit, aby žádný výpočet vůbec nepoznal, že jeho provádění bylo v určitém časovém okamžiku přerušeno a obnoveno až někdy později, zatímco v mezidobí pokračovalo provádění jiných výpočtů. Problém je ale v tom, že jednotlivé výpočty mají kolem sebe své „životní prostředí", které si určitým způsobem „zabydlují", a které se jim při takovémto přerušení nesmí změnit. Neboli: když se určitý výpočet po svém dočasném přerušení dostane opět ke slovu, musí své „životní prostředí" najít přesně v takovém stavu, v jakém se nacházelo v okamžiku přerušení.

Co všechno ale spadá do takovéhoto „životního prostředí", v odborné terminologii označovaného jako kontext? Zcela jistě sem patří aktuální hodnota tzv. čítače instrukcí (registru PC, program counter-u) - protože tato hodnota vyjadřuje místo, ve kterém došlo k přerušení právě prováděného výpočtu. Bez zachování této informace by vůbec nebylo možné se k provádění přerušeného výpočtu někdy později vrátit.

Do kontextu každého konkrétního výpočtu však zcela jistě musíme zařadit i mnoho dalších věcí: obsahy všech registrů procesoru, stav příznaků (flag-ů) a stav zásobníku, kde daný výpočet může mít uloženy své nejrůznější mezivýsledky. Ty však může mít uloženy například i v jiných oblastech paměti, než je zásobník - například v různých datových segmentech. Také ty proto musíme zahrnout do kontextu daného výpočtu. Obecně tam pak musíme zahrnout také celý adresový prostor, který je pro daný výpočet viditelný, protože na kterémkoli místě v tomto adresovém prostoru může být něco relevantního, co nesmí být přepsáno či jinak změněno. Dále bychom do kontextu každého výpočtu měli zahnout například i stav všech vstupně-výstupních obvodů a zařízení, protože každý výpočet může mít v určitém okamžiku jistým způsobem rozpracovány některé vstupně/výstupní operace, a řídit se podle jejich průběhu.

Je toho opravdu hodně, co patří do kontextu každého výpočtu, a co tedy musí zůstat zachováno bez sebemenší změny i při případném přerušení daného výpočtu. V okamžiku, kdy dochází k dočasnému přerušení jednoho výpočtu a jeho vystřídání výpočtem jiným, je pak vlastně třeba vhodně uschovat celý kontext právě přerušovaného výpočtu, a nahradit jej kontextem jiného výpočtu. Dochází tedy k něčemu, co můžeme po právu nazvat přepnutím kontextu (context switch).

Jak ale můžeme tušit z předchozích odstavců, přepnutí kontextu může být značně netriviální záležitostí, náročnou především díky „objemu" celého kontextu. Zvláště jde-li o takové výpočty, které v rámci svého kontextu hospodaří skutečně tak, jako kdyby měli celý počítač jen a jen pro sebe - takovýmto výpočtům je pak skutečně nutné uschovávat vždy celý jejich kontext. Existují ovšem i takové výpočty, které se v tomto ohledu chovají poněkud rozumněji: počítají s tím, že budou často střídány jinými výpočty, a proto se svým kontextem hospodaří účelněji. Jsou zcela záměrně psány tak, aby při jejich „odstavení" bylo nutné uschovat a následně obnovit jen nezbytné minimum informací, obvykle představující jen obsah registrů procesoru, stav příznaků a stav zásobníku, a nikoli například různé oblasti paměti. Takovéto výpočty, kterým se v odborné terminologii říká vlákna (threads), mohou naopak zcela záměrně počítat s tím, že jejich adresový prostor nebude při jejich střídání uschováván a později zase obnovován, ale že bude trvale přístupný všem vzájemně se střídajícím vláknům, které jej tak budou vlastně společně sdílet.

Protipólem vláken (threads) jsou v tomto ohledu takové výpočty, které bychom s jistou dávkou nadsázky mohli označit jako „težkotonážní" - jsou to takové výpočty, při jejichž přerušení se uschovává celý jejich rozsáhlý kontext, a nikoli jen malý objem úzce lokalizovaných dat, jako je tomu v případě vláken. Takovéto „těžkotonážní" výpočty se obecně označují jako procesy (zatímco vlákna se někdy označují také jako „lightweight processes", doslova: „odlehčené procesy").