Linux v příkazech - správa procesů

Práce s procesy v systému, jejich výpis, přesun na pozadí, ukončení a zjišťování, který proces v systému vlastní dané prostředky.

21.9.2004 10:00 | o.k. | přečteno 131563×

Každý program v Linuxu/Unixu se po spuštění stává procesem, který je plně v rukou srdce systému, tedy Linuxového jádra, či kernelu chcete-li. Kernel danému programu přidělí na základě výše jeho priority část paměťového prostoru a případně další systémové prostředky, je-li to vyžadováno. Protože Linux je operační systém, který plně využívá multitasking, bude každý proces ve zjednodušeném slova smyslu "bojovat" o získání co největšího procesorového času. Zde bude potom hrát roli výše priority procesu. Systém vnitřně využívá řadu front a semaforů, kterými řídí procesy a stará se o přidělování procesoru a dalších systémových prostředků. Díky multitaskingu se nám - uživatelům zdá, že v systému běží spousta procesů zároveň. Ano, běží, ale procesor zpracovává v daném čase vždy jen jeden proces (bavím se o jednoprocesorovém PC) a ostatní procesy trpělivě čekají ve frontě na svůj čas, kdy jim bude procesor také přdělen.

Aby nedošlo k mýlce měl bych dodat, že ono přidělování procesoru je opravdu na velmi malé časové okamžiky, aby si někdo třeba nemyslel, že když spustí program OpenOffice, že si tento proces vezme procesor na celou půl minutu než program nastartuje :-) - není tomu tak, to by nebyl multitasking. V průběhu spouštění se dostane k procesoru ještě celá spousta dalších procesů a to opět v závislosti na dané výši jejich momentální priority.

Můžeme se také často setkat s tím, že jeden program po spuštění vytvoří v systému více procesů, což je obvyklé u démonů. A o tom, že mluvím pravdu se budete moci sami přesvědčit použitím jednoho z níže popisovaných programů.

Doufám, že toto úvodní povídání, které jsem se snažil co nejsrozumitelněji podat (zkušení odborníci nechť prominou spoustu úmyslně opominutých věcí a velké zjednodušení výkladu vztahu jádra k procesům) vás neodradilo od poznávání dalších Linuxových příkazů.

Začněme příkazem, který nám podá informaci o procesech, které jsou v systému (úmyslně se vyhýbám spojení "běží v systému"), protože jak uvidíte sami, nemusí tomu tak být. Příkaz pro výpis procesů v systému se nazývá ps (process status).

ps

  PID TTY          TIME CMD
  227 tty1     00:00:01 bash
  286 tty1     00:00:00 ps 

Příkaz ps bez parametrů vypíše pouze procesy uživatele, který tento příkaz spustil a pouze ty procesy, které byly spuštěny ze stejného terminálu jako samotný příkaz ps.

Chceme-li vypsat všechny procesy běžící v systému, tak použijeme následující parametry:

ps ax

  PID TTY      STAT   TIME COMMAND
    1 ?        S      0:04 init
    2 ?        SW     0:00 [kflushd]
    3 ?        SW     0:00 [kupdate]
    4 ?        SW     0:00 [kswapd]
    5 ?        SW     0:00 [keventd]
  139 ?        S      0:00 /sbin/syslogd
  142 ?        S      0:00 /sbin/syslog-ng
  144 ?        S      0:00 /sbin/klogd
  168 ?        S      0:00 /sbin/cardmgr
  181 ?        S      0:00 /usr/sbin/apmd -P /etc/apm/apmd_proxy
  194 ?        S      0:00 /usr/sbin/gpm -m /dev/psaux -t ps2
  220 ?        S      0:00 /usr/sbin/atd
  223 ?        S      0:00 /usr/sbin/cron
  227 tty1     S      0:01 -bash
  228 tty2     S      0:00 -bash
  229 tty3     S      0:00 -bash
  272 tty2     S      0:13 vim bash_proces.txt
  369 tty3     S      0:00 bash
  371 tty1     R      0:00 ps ax 

Asi budete mít tento výpis podstatně delší, každopádně je z něj dobře patrné, že pracuji v editoru vim na tomto souboru, který jsem si pracovně nazval bash_proces.txt. Také můžete vidět, že na posledním místě je právě mnou spuštěný proces ps ax. Možná vás trochu mate ten druhý bash spuštěný ve třetí konsoli - je to nově spuštěný shell uživatele root, protože jsem se v této konsoli přihlásil jako normální uživatel a potom jsem spustil příkaz su.

Ve stručnosti zde vysvětlím význam jednotlivých sloupců. První sloupec, označen jako PID, udává identifikační číslo procesu (které je v systému jedinečné). Proces s názvem init, dalo by se říci rodičovský proces všech procesů v sytému bude mít vždy číslo 1. Druhý sloupec TTY podává informaci o tom, ze kterého terminálu byl proces spuštěn. Pokud zde bude znak ?, znamená to, že daný proces není svázán s žádným terminálem (což jsou obvykle procesy spouštěné při inicializaci systému). Další sloupec je již významnější, neboť podává informaci o tom v jakém stavu se daný proces nachází. Asi by nebylo od věci velmi stručně popsat základní stavy ve kterých se může proces nacházet.

S proces usnul - čeká až na něj přijde řada a bude mu přidělen procesor
W paměťový prostor vyhrazený danému procesu byl kompletně uložen na disk (odswapován)
R proces je právě zpracováván procesorem
T proces byl pozastaven
D proces je v nepřerušitelném spánku (v tomto stavu jsou většinou procesy svázané s I/O operacemi)
Z proces, jehož rodičovský proces již ukončil svoji činnost (třeba díky nějaké závažné chybě a nechal po sobě sirotka. Rodičem Zombie procesu se stává Init). Zombie procesy v systému jsou obvykle důsledkem špatně napsaných programů.
L proces má uzamknuté stránky v paměti - platí obvykle pro procesy pracující v reálném čase
< proces s vysokou prioritou
N proces s nízkou prioritou

Dalším sloupcem je sloupec TIME, který podává informace o procesorovém času, který byl danému procesu již přidělen.

Posledním sloupcem v našem zkráceném výpisu je sloupec podávající informace o příkazu a jeho parametrech, což je pro nás hlavní informace o daném procesu.

Příkaz ps má nepřeberné množství voleb, díky nimž může výpis procesů vypadat jednodušeji, či naopak velmi podrobně a má také mnoho klonů, které se mohou více či méně lišit a to jak v sémantice parametrů, tak i ve výstupu. V Linuxu se převážně používa GNU verze, která umí napodobovat chování prakticky libovolného klonu ps.

ps aux
ps aef

Příkaz ps má bratříčka a tím je příkaz pstree, který nám vypisuje stromovou strukturu procesů ze které je dobře patrné rodičovství a posloupnost procesů.

pstree -a

init)
  |-apmd) -P /etc/apm/apmd_proxy
  |-atd)
  |-bash)
  |   `-pstree) -a
  |-bash)
  |   `-vim) bash_proces.txt
  |-bash)
  |   `-bash)
  |-cardmgr)
  |-cron)
  |-gpm) -m /dev/psaux -t ps2
  |-(keventd)
  |-(kflushd)
  |-klogd)
  |-(kswapd)
  |-(kupdate)
  |-syslog-ng)
  `-syslogd)

Dalším příkazem, který vypisuje aktuálně běžící procesy a spoustu dalších důležitých systémových informací je příkaz top. Tento příkaz narozdíl od předchozího příkazu ps nevypisuje pouze výpis aktuálního stavu procesů v systému, ale dokáže tento výpis dynamicky po určitých časových intervalech měnit. Díky tomu můžeme v reálném čase sledovat změny stavu procesů, jejich "boj" o procesor, aktuální velikost paměti, které procesy alokují a spoustu dalších užitečných informací. Defaultní časový interval změny výpisu je nastaven na 5 sekund, lze jej však změnit pomocí parametru -d. Pozor na to, že samotný proces top se bude objevovat v horní části jeho výpisu, protože je poměrně náročný na systémové prostředky a zmenšení intervalu výpisu bude náročnost na systémové prostředky ještě zvyšovat.

top -b

top-10:02:37 up 69 days, 34 min, 7 users, load average: 0.00, 0.10, 0.15
Tasks: 127 total,   1 running, 125 sleeping,   1 stopped,   0 zombie
Cpu(s): 11.2% us, 1.7% sy, 0.8% ni, 84.3% id, 1.7% wa, 0.1% hi, 0.2% si
Mem:    385836k total,   380732k used,     5104k free,    42856k buffers
Swap:   497972k total,   232456k used,   265516k free,    73372k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 7923 root      15   0  184m  86m  79m S  2.0 23.0 632:56.88 X
27569 ondra     15   0  136m  69m  36m S  2.0 18.4  73:56.43 firefox-bin
23790 ondra     15   0  2168  972 1964 R  2.0  0.3   0:00.02 top
    1 root      16   0  1580  164 1424 S  0.0  0.0   0:05.97 init
    2 root      34  19     0    0    0 S  0.0  0.0   0:01.03 ksoftirqd/0
    3 root       5 -10     0    0    0 S  0.0  0.0   0:17.46 events/0
    4 root       5 -10     0    0    0 S  0.0  0.0   0:33.54 kblockd/0
    5 root      15   0     0    0    0 S  0.0  0.0   0:01.78 kapmd
    8 root      15   0     0    0    0 S  0.0  0.0   2:23.28 kswapd0
    9 root      10 -10     0    0    0 S  0.0  0.0   0:00.00 aio/0
   11 root      19   0     0    0    0 S  0.0  0.0   0:00.00 kseriod
   15 root      15   0     0    0    0 S  0.0  0.0   0:31.93 kjournald
  166 root      15   0     0    0    0 S  0.0  0.0   0:03.37 khubd
  363 root      15   0     0    0    0 S  0.0  0.0   0:55.04 kjournald
                               . . .

Možná by neškodil zběžný popis jednotlivých sloupců ve výstupu příkazu top. Výpis se v jednotlivých distribucích může trochu lišit, proto i popis položek je trochu odlišný od výpisu výše.

První sloupec (PID) udává identifikační číslo procesu, což je stejné jako u výpisu příkazu ps. Druhý sloupec (USER) vypisuje identitu (uživatele) pod níž daný proces běží. Třetí sloupec (PRI) vypisuje aktuální výši priority daného procesu. Čtvrtý sloupec udává výši priority zadanou příkazem nice (záporná čísla udávají vyšší prioritu - příkaz nice bude popisován níže v tomto dílu). Další sloupec SIZE udává celkovou velikost procesu v paměti (velikost je udávána v kB a je to velikost kódu + velikost zásobníku + velikost dat). V pořadí šestý sloupec - RSS - udává celkovou velikost (v kB) použité fyzické paměti pro daný proces. Sloupec SHARE obsahuje velikost sdílené paměti, sloupec STAT udává stav procesu (indikace stavu je stejná jako u příkazu ps výše). Sloupec %CPU obsahuje procentuální informace o využití procesoru daným procesem v okamžiku výpisu a další sloupec %MEM informuje o procentu využití fyzické paměti daným procesem. Sloupec TIME udává celkový procesorový čas po který byl daný proces od spuštění až do okamžiku výpisu zpracováván (z tohoto času je patrné, že spousta procesů má procesorový čas velmi malý, protože mnoho z nich často čeká na nějaké I/O operace). Poslední sloupec COMMAND popisuje daný proces/příkaz.

V tomto odstavci si povíme něco o spouštění příkazů na pozadí, o zastavení procesu a o přepínání procesů z popředí na pozadí a naopak. K čemu je toto vlastně dobré? Asi by se vám nelíbilo, kdyby vám každý spuštěný příkaz zabral jednu konsoli (terminál) a pro spuštění dalšího příkazu byste se museli přesunout do další konsole, či spustit další terminál. Naštěstí má toto Linux vyřešené a umožňuje přesunout spuštěný program - v tuto chvíli již tedy proces v systému, na "pozadí". K tomuto přesunu slouží parametr &, který se zapisuje za daný příkaz (tedy i za případné parametry daného příkazu).

rm -rf big_folder &

V tuto chvíli nemusím čekat na smazání velkého adresáře se spoustou souborů a mohu ihned zadávat další příkazy, zatímco na pozadí systém provádí mazání adresáře, všech jeho podadresářů a souborů.

Na pozadí lze přesunout i již běžící proces. Musíme tento proces nejprve pozastavit (což provedeme stiskem kláves CTRL+z), abychom se dostali k příkazové řádce a pak jej přesuneme na pozadí k čemuž slouží příkaz bg.

Výstup výše uvedeného bude vypadat následovně:

rm -rf big_folder
(pozastavíme tento spuštěný proces stiskem kláves CTRL+z)

[1]+  Stopped           rm -rf big_folder
bg

[1]+ rm -rf big_folder &

Jak vidíte z tohoto výstupu proces s číslem [1] byl přesunut na pozadí, kde nerušeně pracuje. Značka + ve výpisu znamená, že tento proces byl naposledy přesunut na pozadí a při použití příkazu fg (příkaz pro přesun procesu na popředí) bez parametrů to bude právě tento proces, který se zase přesune na popředí.

Takto můžeme v jednom terminálu pracovat se spoustou příkazů najednou. Procesy budou pro daný terminál/konsoli číslovány vždy od čísla 1. Výpis procesů (pozastavených či pracujících na pozadí) v daném terminálu zajišťuje příkaz jobs.

jobs

[1]   Stopped                 man 7 signal
[2]+  Stopped                 vim /etc/resolv.conf
[3]   Stopped                 top
[4]-  Stopped                 vim bash_proces.txt

Pokud máme v jedné konsoli více pozastavených, či na pozadí pracujících procesů (třeba jako já ve výpisu výše), odkazujeme se na ně pomocí jejich čísla. Pokud se tedy chci vrátit k pozastavenému procesu top, provedu to jednoduše příkazem

fg %3

Ještě pro zopakování - příkaz fg bez parametru by na popředí aktivoval proces s číslem 2, tedy editor vim.

Zrušení procesu (či poslání signálu danému procesu, chcete-li) se provádí příkazem kill nebo případně příkazem killall. Rozdíl mezi těmito dvěma příkazy je pouze v tom, že příkaz kill využívá k identifikaci daného procesu jeho identifikační číslo (PID) - tedy číslo v prvním sloupci výpisu příkazu ps, naproti tomu příkaz killall využívá k identifikaci procesu jeho jméno a dokáže tak najednou obsloužit více procesů se stejným jménem, což je vhodné zejména při ukončování démonů a jejich případných potomků.

Jednotlivé signály, které můžeme procesům poslat zde rozebírat nebudu. Seznam těchto signálů a jejich význam naleznete takto:

man 7 signal

nebo případně

kill -l

Proces vim (konkrétně pak instanci vim bash_proces.txt) tedy ukončíme jedním z těchto tří možných příkazů

kill 272    # viz PID ve vypisu vyse
killall vim # pozor, takto jsem si ukoncil 
            # i druhou instanci editoru vim (vim /etc/resolv.conf)
kill %4     # za predpokladu, ze jsem ve stejnem terminalu 
            # ve kterem jsem tento proces spustil

Takto bez použití dalšího parametru jsem procesu poslal signál TERM (číslo 15), tedy signál pro normální ukončení při kterém má proces možnost zamést po sobě v systému stopy (zavřít po sobě soubory, korektně ukončit spojení a podobně). Pokud by se proces bránil a nechtěl by se ukončit, můžeme použít násilnější variantu jako například

kill -9 272

Jednotlivé signály můžeme zapisovat buď ve zkrácené číselné formě, pokud si ji pamatujeme nebo v podobě názvu signálu. Následující příkaz je totožný s příkazem uvedeným výše, akorát použijeme zápis signálu pomocí jeho názvu.

kill -SIGKILL 272

Dalším signálem, který se také velice často využívá je signál úrovně 1 (SIGHUP), který se využívá zejména u démonů a slouží ke znovunačtení konfiguračních souborů, aniž bychom museli ukončit a znovu spustit daného démona. Pozor, není to však daným pravidlem, protože některé druhy démonů pro znovunačtení svých konfiguračních souborů používají signály úrovně SIGUSR1 či SIGUSR2.

Dalším příkazem, který si v tomto díle osvětlíme a který úzce souvisí se správou procesů bude příkaz sloužící ke změně priority daného procesu. Jedná se o příkaz nice.

Jistě si ještě vzpomenete na můj úvodní stručný popis boje jednotlivých procesů o systémové prostředky. Linux nám dává neomezené možnosti a proto můžeme tento boj částečně ovlivnit i my.

Pomocí příkazu nice můžeme jako běžný uživatel měnit prioritu námi spouštěných procesů a to v rozsahu od 0 do +19. Jako běžný uživatel můžeme tedy prioritu pouze snižovat od původní hodnoty (obvykle hodnota 0), kterou mimo jiné zjistíme příkazem nice bez parametru.

Jako uživatel root můžeme prioritu jednotlivých procesů jak snižovat, tak i zvyšovat a to v rozmezí hodnot -20 (nejvyšší priorita) až +19 (nejnižší priorita).

Příkaz pro snížení priority u procesu rm -rf big_folder bude tedy vypadat následovně

nice -10 rm -rf big_folder 

Zvýšení priority vypadá následovně

nice --10 rm -rf big_folder 

nebo také

nice -n -10 rm -rf big_folder 

Prioritu je výhodné snižovat zejména u operací, které využívají čtení či zápis na disk, tedy například při vyhledávání souborů v celém souborovém systému nebo při zálohování. Ještě bych měl dodat, že příkazem nice můžeme měnit prioritu pouze u spouštěného procesu, nikoliv u již běžícího procesu v systému.

Pro změnu priority procesu běžícího v systému slouží příkaz renice. Lze jím měnit priorita procesu (či více procesů najednou) na základě PID procesu, nebo na základě vlastníka procesu či skupinového vlastníka procesu. Běžný uživatel může měnit prioritu pouze svých procesů a navíc může prioritu pouze snižovat stejně jako tomu bylo u příkazu nice.

renice +10 272

272: old priority 0, new priority 10

Tímto jsem snížil prioritu u procesu vim bash_proces.txt.

Posledním příkazem, který si v tomto díle probereme bude příkaz, díky němuž se daný proces stane imunní vůči některým signálům - jedná se o příkaz nohup. Je obvykle vhodný v případě, kdy se chceme odhlásit z dané konsole a přesto chceme, aby námi spuštěný proces v dané konsoli pracoval i nadále po našem odhlášení.

Jediným parametrem příkazu nohup je název spouštěného programu včetně jeho parametrů.

nohup yes &

Takto bude program yes stále pracovat i po mém odhlášení z dané konsole a výstup z tohoto programu + případný chybový výstup bude přesměrován do souboru $HOME/nohup.out. Toto raději nezkoušejte na delší dobu, jinak vás správcové systému poženou :-)

Program nohup nepřesouvá automaticky daný proces na pozadí, přesun na pozadí je třeba provést pomocí &, či proces pozastavit a přesunout jej na pozadí pomocí příkazu bg.

Doufám, že vaše hrátky s procesy neskončily nějak tragicky a že již máte trochu přehled nad tím, co se ve vašem systému děje. Pár některých užitečných příkazů se sem již nevešlo (například lsof a fuser), k nim se určitě vrátíme v některém z dalších dílů.

Zdroje

Za věcnou kritiku a doplnění bych chtěl poděkovat Honzovi Houšťkovi.

Online verze článku: http://www.linuxsoft.cz/article.php?id_article=409