Řízení úloh (Unix)

Řízení úloh v Unixu a v operačních systémech z něho odvozených je (obvykle interaktivní) ovládání úloh pomocí unixového shellu. Úloha je proces nebo skupina procesů vytvořená v shellu zadáním jednoho příkazu, který však především díky používání rour může spustit více spolupracujících procesů.

Řízení úloh v Unixu umožňuje vybranou úlohu dočasně pozastavit, obnovit její provádění, převést provádění úlohy do pozadí nebo do popředí, nebo úlohu předčasně ukončit. Takto pojaté řízení úloh je jednou z možností využívání multitaskingu v Unixu dostupnou i při práci v prostředí příkazového řádku; v mnoha ohledech se odlišuje od řízení úloh v jiných operačních systémech, které se obvykle omezuje na popis potřeb úlohy a výběr další úlohy při dávkovém zpracování.

Historie editovat

Původním záměrem řízení úloh v Unixu bylo umožnit uživateli spustit více úloh (multitasking) i v prostředí příkazového řádku v rámci jedné relace (jednoho přihlášení). Uživatel mohl úlohy, jejichž provádění trvá dlouho, spouštět v pozadí. Taková úloha na rozdíl od úlohy v popředí nepřijímá vstup z terminálu, ale její výstupy jsou stále zobrazovány na obrazovce; pokud to uživateli nevyhovuje, musí výstupy přesměrovat do souboru. Řízení úloh, které umožňuje uživateli úlohu spuštěnou v popředí převést do pozadí a vybírat z několika úloh, která poběží v popředí, poprvé implementoval Jim Kulp v C shellu[1] při své práci v Mezinárodním institutu pro aplikovanou systémovou analýzu (IIASA) v Rakousku, přičemž využil funkce z jádra 4.1BSD. Funkcionalita byla následně implementována v Korn shellu vyvíjeného v Bellových laboratořích a začleněna do Bourne shellu pro SVR4; od té doby je dostupná ve většině moderních Unixových shellů.

Procesy a úlohy vytvářené shellem editovat

Po přihlášení k počítači s Unixem nebo příbuzným operačním systémem z terminálu (nebo emulátoru terminálu) se uživateli spustí interaktivní unixový shell, který čte příkazy zadávané uživatelem z klávesnice terminálu, některé příkazy vykonává sám (tzv. vnitřní příkazy), ale pro provádění většiny příkazů spouští samostatné programy. Spuštěním programu vznikne proces, kterému shell poskytne vstup z klávesnice terminálu a výstup na jeho obrazovku v podobě standardních proudů (standardního vstupu a standardního výstupu). Po ukončení programu se ovládání vrací shellu, který je spuštěn po celou dobu přihlášení a ukončuje se až při odhlášení uživatele.

Řízení úloh poněkud komplikuje možnost vytváření složitých konstrukcí, ve který je více dílčích příkazů spojeno rourami. Pokud např. uživatel zadá příkaz pro výběr řádků souboru, které obsahují slovo „titul“, jejich abecední setřídění a zobrazení po obrazovkách:

grep titul soubor.txt | sort | less

shell spustí tři procesy: jeden pro grep, další pro sort, a další pro less. Aby řízení úloh umožňovalo ovládat takto spjaté příkazy shellem jako jeden celek, byl navržen koncept skupiny procesů, kterou norma POSIX definuje takto:[2]


Skupina procesů je sada procesů, které tvoří příkazovou kolonu, případně další procesy, které jsou potomky těchto procesů.


Koncept úlohy převádí koncept jediného příkazu (zadaného v shellu) na jeden nebo více procesů (v operačním systému), které příkaz vyvolá. Úloha tvořená několika procesy vzniká díky tomu, že procesy mohou vytvářet další procesy-potomky, a příkaz shellu se může skládat z kolony několika vzájemně komunikujících procesů.

Úlohy jsou spravované operačním systémem jako jediná skupina procesů, kterou shell reprezentuje jako úlohu.

Na úlohu se lze odkazovat pomocí manipulátoru,[pozn. 1] který se nazývá identifikátor úlohy, anglicky job control job ID, který vnitřní příkazy shellu používají pro odkazy na jednotlivé úlohy. ID úloh začínají znakem %; %n identifikuje úlohu n, zatímco %% identifikuje aktuální úlohu. Další ID úloh definuje standard POSIX.[3] V neformálním použití mluvíme o „čísle úlohy“ nebo „identifikátoru úlohy“; v dokumentaci shellu bash se pro číslo úlohy se znakem procento používá označení jobspec.[4]

Řízení úloh a identifikátory úloh se typicky používají pouze při interaktivní práci, kde zjednodušuje odkazování na skupiny procesů; při skriptování se místo toho používají identifikátory skupiny procesů (anglicky Process Group ID, PGID), protože jsou přesnější a robustnější, a řízení úloh je ve skriptech v bashi implicitně zakázáno.

Řízení úloh je funkcionalita vyvinutá s cílem umožnit uživateli spouštět procesy v pozadí, převést proces běžící v popředí do pozadí, a obráceně proces v pozadí do popředí, pozastavit nebo jej ukončit.

Ovládání pomocí signálů editovat

Jiným způsobem ovlivňování procesů je zasílání signálů. Některé signály lze vyvolat stisknutím určité kombinace kláves, ale jejich zpracování je zcela odlišné než obvyklý vstup z klávesnice:

  • Provádění úlohy v popředí lze ukončit stisknutím Control+C. Tím se skupině procesů pošle signál „přerušení“ (SIGINT), který implicitně ukončí proces, ale proces může tento signál zachytit a ignorovat nebo provést jinou akci.
  • Provádění úlohy v popředí lze pozastavit stisknutím kombinace kláves Control+Z. Tím se skupině procesů pošle signál „terminál stop“ (SIGTSTP). SIGTSTP implicitně způsobí pozastavení procesů, které jej přijmou, a vrácení řízení shellu. Procesy si však mohou zaregistrovat handler, který jim umožní signál SIGTSTP ignorovat. Pozastavení procesu lze provést také signálem „stop“ (SIGSTOP), který nemůže být zachycen ani ignorován.

Příkazy a implementace editovat

Standard POSIX definuje dva příkazy převzaté z Korn shellu.[5]

  • bg pro obnovení (pokračování) provádění pozastavené úlohy v pozadí
  • fg pro obnovení běhu úlohy v popředí

Shell si typicky udržuje seznam úloh v tabulce úloh. Příkaz jobs vypisuje úlohy v pozadí z tabulky úloh, spolu s číslem a stavem (pozastavená nebo běžící) úlohy. Relace končí, když se uživatel odhlásí (opustí shell, což ukončí proces, který vede relaci), proces shellu pošle SIGHUP všem úlohám, a než sám skončí, čeká až skončí všechny procesy ze skupiny.

Příkaz disown slouží pro odstranění úlohy z tabulky úloh, takže po ukončení relace se skupinám procesů neposílá signál SIGHUP, a shell nečeká na jejich ukončení. Stanou se z nich osiřelé procesy, které mohou být ukončeny operačním systémem, ale častěji jsou převzaty procesem init (jádro nastaví, že jejich rodičovský proces je proces init) a pokračují v běhu jako démoni. Zabránit tomu, aby se při odhlášení úloha ukončila, lze použitím příkazu nohup nebo použitím terminálového multiplexoru.

Pozastavenou úlohu lze obnovit na pozadí vnitřním příkazem shellu bg nebo jako úlohu v popředí příkazem fg. V obou případech shell vhodným způsobem přesměruje vstupy a výstupy, a procesu pošle signál SIGCONT, který způsobí, že operační systém obnoví jeho provádění. V bashi lze program spustit na pozadí zakončením příkazu znakem ampersand (&); v tomto případě zůstává standardní výstup stále nasměrován na terminál (což může vést k tomu, že výstup se bude míchat výstupy jiných programů), ale číst z terminálového vstupu nemůže.

Procesu v pozadí, který se snaží číst ze svého řídícího terminálu nebo na něj zapisovat, bude poslán signál SIGTTIN (pro vstup) nebo SIGTTOU (pro výstup). Tyto signály implicitně proces pozastaví, ale jejich chování lze změnit. Shellové skripty často upravují implicitní reakci na signál SIGTTOU, takže proces v pozadí implicitně doručí svůj výstup řídícímu terminálu.

Shelly kompatibilní s bashem mají vestavěný příkaz kill (různý od programu /bin/kill), jehož parametrem může být nejen ID procesu, ale i ID úlohy (před kterým je třeba pro rozlišení od identifikátoru procesu psát %), což způsobí poslání signálu celé skupině procesů. Přestože se příkaz jmenuje kill (zabít), umožňuje poslat procesu nebo úloze libovolný signál, i takový, který ukončení úlohy nebo procesu nezpůsobí; skutečné ukončení způsobí zaslání signálu SIGKILL nebo SIGTERM (který se použije, pokud není zadáno číslo signálu).

Pro zasílání signálů procesům nebo úlohám má bash a z něho odvozené shelly vestavěný příkaz kill. Jeho jméno vychází z jeho nejobvyklejšího použití pro ukončení úlohy, jehož se dosáhne zasláním signálu SIGKILL nebo SIGTERM (SIGTERM je signál, který příkaz kill použije implicitně, pokud není zadáno jméno nebo číslo jiného signálu), navzdory jeho jménu jej však lze použít i pro zasílání signálů, které ukončení procesu nebo úlohy nezpůsobují.

Odkazy editovat

Poznámky editovat

  1. „Manipulátorem“ (anglicky handle) obvykle nazýváme abstraktní referenci na prostředek, který spravuje jiný modul, než který jej používá. V tomto případě identifikátor úlohy (anglicky task ID) je abstraktní reference shellu na skupinu procesů, která je spravována operačním systémem.

Reference editovat

V tomto článku byl použit překlad textu z článku Job control (Unix) na anglické Wikipedii.

  1. Předmluva od Billa Joye in ANDERSON, Gail; ANDERSON, Paul, 1986. The UNIX C Shell Field Guide. [s.l.]: Prentice-Hall. Dostupné online. ISBN 0-13-937468-X. S. xvii. 
  2. IEEE Std 1003.1-2001, Section 3.201, Job
  3. IEEE Std 1003.1-2001, Section 3.203, Job Control Job ID
  4. Bash Reference Manual [online]. [cit. 2024-04-24]. Kapitola Job Control Basics. Dostupné online. 
  5. bg – manuálová stránka The Open Group Shell and Utilities Reference, Single UNIX Specification, Version 4 from The Open Group; fg – manuálová stránka The Open Group Shell and Utilities Reference, Single UNIX Specification, Version 4 from The Open Group:

Literatura editovat

Související články editovat

Externí odkazy editovat