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ů.
man ps
, man pstree
man top
man nice
man nohup
help help
:-)man kill
, help kill
, man killall
man bash
, sekce JOB CONTROL, viz též help jobs fg bg
man lsof
man fuser
Za věcnou kritiku a doplnění bych chtěl poděkovat Honzovi Houšťkovi.