
Procesy w systemach GNU/Linux

Czym jest proces? Co to jest program i czym różni się od procesu? Jak monitorować oraz zarządzać procesami w Linuksie? Na te oraz inne ważne z punktu widzenia administratora pytania odpowiemy w tym artykule.
Czym jest proces? Co to jest program i czym różni się od procesu? Jak monitorować oraz zarządzać procesami w Linuksie? Na te oraz inne ważne z punktu widzenia administratora pytania odpowiemy w tym artykule.
Programem możemy ogólnie nazwać zestaw instrukcji prowadzących do wykonania określonego zadania. Jest to twór statyczny zapisany w pamięci komputera najczęściej jako plik wykonywalny bądź skrypt powłoki. Przykładem programu może być zarówno polecenie mv
, jak i dużo bardziej skomplikowany klient poczty Thunderbird
.
Procesem nazwiemy wykonywaną podczas działania systemu instancję programu wraz z dodatkowymi wykorzystywanymi przez niego zasobami, takimi jak przestrzeń pamięci czy wskaźniki do otwartych plików.
Ten sam program może być wykonywany wielokrotnie. Co za tym idzie, może być odpowiedzialny za pojawienie się w systemie wielu procesów. Możemy je rozróżnić dzięki unikalnemu ponumerowaniu każdego z nich, w systemach linuksowych nazwanemu pid
(ang. process ID).
Init
Pierwszym procesem użytkownika uruchamianym w systemie z pid=1
jest tak zwany init (ang. initialization). W systemach Enterprise od wersji siódmej rolę tę spełnia systemd
. Do zadań inita należy tworzenie oraz zarządzanie pozostałymi procesami w przestrzeni użytkownika. Będzie on „przodkiem” wszystkich pozostałych procesów oraz ostatnim procesem działającym w systemie.
Pogromca zombie
Każdy proces poza pid
posiada również ppid
– identyfikator swojego rodzica, czyli procesu, z którego został utworzony oraz gpid
, czyli identyfikator grupy procesów. Jak już wcześniej wspomnieliśmy, pierwszym w przestrzeni użytkownika procesem w systemie jest init. Jest on uruchamiany przez jądro i nie posiada ppid
. Jeśli któryś z rodziców zakończy się przed zakończeniem działania wszystkich procesów dzieci („osieroci” swoje dzieci), rolą init będzie ich „adopcja”, czyli ich ppid
zostanie zmienione na 1.
W systemach z
systemd
rolę adoptowania osieroconych procesów przejąłkthreadd
uruchamiany zpid=2
Każdy proces-dziecko w momencie zakończenia działania zwalania wszystkie wykorzystywane zasoby i czeka na reakcję rodzica. Taki proces, oczekujący już tylko na zwrócenie swojego statusu zamknięcia, nazywamy procesem zombie. Zazwyczaj proces-rodzic zajmuje się prawidłowym zabijaniem swoich dzieci, jednak jeśli zombie został osierocony, jego prawidłowym zakończeniem zajmuje się init. Przez to zwyczajowo init nazywa się po angielsku zombie killer albo child reaper, co można przełożyć jako „pogromca zombi” i „ponury żniwiarz dzieci”.
Planista (ang. scheduler)
GNU/Linux to wielowątkowy, wieloprocesowy czy też wielozadaniowy system operacyjny. Oznacza to, że dąży on do maksymalnego wykorzystania CPU – najcenniejszego zasobu w komputerze. W Linuksie za zoptymalizowane wykorzystanie zasobów odpowiada planista (ang. scheduler). Sprawuje on pieczę nad kolejką procesów oraz przydziela odpowiednim procesom czas procesora. Procesor wykonuje instrukcje w zawrotnym tempie, ma jednak małą, fizycznie ograniczoną ilość rdzeni. Zatem, aby rozdzielać efektywnie czas procesora, planista musi mieć możliwość efektywnego przełączania pomiędzy procesami obecnie wykonywanymi a tymi czekającymi w kolejce.
W systemach linuksowych każdy proces posiada następujące atrybuty:
- program, który wykonuje
- kontekst
- uprawnienia
- przydzielone mu zasoby.
Kluczowym dla planisty atrybutem jest kontekst. W każdym momencie wykonywania proces może zapisać swój stan, czyli informacje o stanie rejestrów procesora, lokalizację, w której wykonywany jest program, pamięć itp. Wszystkie te informacje nazywamy kontekstem. Dzięki temu, że są one zapisane przez proces, planista w każdym momencie może w szybki i efektywny sposób wywłaszczyć obecnie przydzielony do CPU proces i oddać procesor innemu procesowi z kolejki. Daje to możliwość obsłużenia wielu procesów na jedynie kilku wątkach procesora.
Nieco praktyki
W celu efektywnego zarządzania procesami powinniśmy mieć możliwość wglądu w listę tych obecnie działających w systemie. Listę taką możemy uzyskać przy pomocy polecenia ps
(ang. process status). Domyślnie bez podania żadnych opcji otrzymamy informację na temat procesów podpiętych pod obecnie aktywną powłokę:
┌cmd@thinkpad-t480 ~ └> ps PID TTY TIME CMD 6610 pts/4 00:00:00 fish 7038 pts/4 00:00:00 ps
By uzyskać informacje na temat wszystkich procesów w systemie, możemy skorzystać z następujących opcji ps
:
a
– wyświetla wszystkie procesy, a nie tylko te należące do użytkownikau
– wyświetlanie w sposób bardziej przyjazny użytkownikowix
– wyświetla wszystkie procesy, niezależnie od tego, do jakiego wirtualnego terminala są podpięte.
┌cmd@thinkpad-t480 ~ └> ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 193956 8424 ? Ss Mar05 0:22 /usr/lib/systemd/systemd --switched-root --system --deserialize 23 root 2 0.0 0.0 0 0 ? S Mar05 0:00 [kthreadd] root 3 0.0 0.0 0 0 ? I< Mar05 0:00 [rcu_gp] root 4 0.0 0.0 0 0 ? I< Mar05 0:00 [rcu_par_gp] root 6 0.0 0.0 0 0 ? I< Mar05 0:00 [kworker/0:0H-kb] root 8 0.0 0.0 0 0 ? I< Mar05 0:00 [mm_percpu_wq] root 9 0.0 0.0 0 0 ? S Mar05 0:18 [ksoftirqd/0] …output truncated for clarity…
Procesy wypisane w kwadratowych nawiasach ([]) są procesami uruchomionymi bezpośrednio przez jądro systemowe
Program ps
udostępnia nam informację na temat statusu systemu w momencie wywołania komendy. W celu otrzymania bardziej interaktywnego i aktualizowanego w czasie rzeczywistym statusu systemu powinniśmy sięgnąć po top
bądź nowsze htop
. Obydwa programy wyświetlają w górnej części nieco poglądowych informacji na temat systemu, takich jak użycie pamięci oraz procesora czy zestawienie informacji na temat ilości procesów w systemie. Zachęcamy do zapoznania się z artykułem TOP w Linuxie, Htop – jeszcze lepszy monitor systemów oraz naszym poradnikiem dotyczącym top:
https://www.youtube.com/watch?v=MrfJryQ7C9Y
Każdy proces posiada z góry ustalone limity zasobów, z których może korzystać. W celu ich wyświetlenia oraz ustawienia sięgniemy po narzędzie ulimit
. Wywołanie ulimit -a
wyświetli wszystkie limity dla procesów uruchamianych przez obecnego użytkownika.
┌cmd@thinkpad-t480 ~ └> ulimit -a Maximum size of core files created (kB, -c) 0 Maximum size of a process’s data segment (kB, -d) unlimited Maximum size of files created by the shell (kB, -f) unlimited Maximum size that may be locked into memory (kB, -l) 64 Maximum resident set size (kB, -m) unlimited Maximum number of open file descriptors (-n) 1024 Maximum stack size (kB, -s) 8192 Maximum amount of cpu time in seconds (seconds, -t) unlimited Maximum number of processes available to a single user (-u) 4096 Maximum amount of virtual memory available to the shell (kB, -v) unlimited
W celu ustalenia identyfikatora procesu, pod jakim został uruchomiony konkretny program, możemy skorzystać z programu autodeskryptywnego polecenia pidof
:
┌cmd@thinkpad-t480 ~ └> pidof firefox 26373 ┌cmd@thinkpad-t480 ~ └> pidof fish 31826 22418 22188 19924 6650 1455
Jak widać na powyższym przykładzie, w przypadku, gdy w systemie uruchomiona jest więcej niż jedna instancja programu, zostanie wyświetlona lista ID wszystkich procesów danego programu.
Procesy w tle i pierwszoplanowe
Pracując w terminalu, wykonujemy różne programy. Jeśli są to programy interaktywne, takie jak top
, przechwytują one wciśnięcia klawiszy i wykonują różne działania. W przypadku programów pokroju cat
w standardowym strumieniu wyjścia będą wyświetlane dane lub program będzie oczekiwał danych wejściowych ze standardowego strumienia. O procesach takich „normalnie” uruchomionych programów mówimy, że są to procesy pierwszoplanowe. Można również uruchamiać procesy w tle (ang. background). Kluczowymi dla zaprezentowania poniższego przykładu będą jeszcze skróty klawiszowe CTRL+c
oraz CTRL+z
, które kolejno wysyłają do procesu sygnał przerwania i zatrzymania, co efektywnie oznacza przerwanie działania w pierwszym przypadku oraz zatrzymanie działania programu w drugim.
Praktyczne zastosowanie wiedzy z tego podrozdziału najlepiej pokażą przykłady. Do tego celu posłużymy się trzema programami:
jobs
– wyświetla obecnie uruchomione w powłoce zadania/procesybg [PID]
(ang. background) – uruchamia proces o podanympid
w tlefg [PID]
(ang. foreground) – uruchamia proces o podanympid
jako proces pierwszoplanowy.
Dla bg
i fg
, zamiast identyfikatora procesu, możemy podać indeks zadania wyświetlony przy pomocy polecenia jobs
poprzedzonego znakiem procentu.
Następnie wykonujemy polecenie, które uruchomi nową powłokę bash i wykona skrypt, który będzie czekał przez zadany czas (w sekundach), a następnie wypisze na standardowy strumień wyjścia tekst. Zakończenie komendy znakiem &
spowoduje, że polecenie zostanie wykonane w tle.
bash -c 'sleep 3600; echo "zadanie NUMER"' &
Przejdźmy zatem do naszego przykładu.
┌cmd@thinkpad-t480 ~ └> bash -c 'sleep 3600; echo "zadanie1"' & ┌cmd@thinkpad-t480 ~ └> bash -c 'sleep 3600; echo "zadanie2"' & ┌cmd@thinkpad-t480 ~ └> bash -c 'sleep 10; echo "zadanie3"' & ┌cmd@thinkpad-t480 ~ └> jobs Job Group CPU State Command 3 1130 0% running bash -c 'sleep 10; echo "zadanie3"' & Job Group CPU State Command 2 836 0% running bash -c 'sleep 3600; echo "zadanie2"' & Job Group CPU State Command 1 520 0% running bash -c 'sleep 3600; echo "zadanie1"' &
Uruchomiliśmy trzy procesy, co widać w ładnej tabelce wypisanej przez program jobs
. W pierwszej kolumnie znajdują się: numer indeksu programu, który możemy użyć w programach fg
i bg
(pamiętając o poprzedzeniu ich znakiem procentu), pid
procesu, status i na końcu polecenie, które powołało proces do życia.
Ostatnia komenda po dziesięciu sekundach zakończy czekanie i wypisze na ekran test „zadanie3”:
┌cmd@thinkpad-t480 ~ └> zadanie3 Job 3, “bash -c 'sleep 10; echo "zadani…” has ended ┌cmd@thinkpad-t480 ~ └> jobs Job Group CPU State Command 2 836 0% running bash -c 'sleep 3600; echo "zadanie2"' & Job Group CPU State Command 1 520 0% running bash -c 'sleep 3600; echo "zadanie1"' &
Jak widać, jobs
wyświetla już tylko dwa zadania. Uruchomimy teraz drugi proces jako proces pierwszoplanowy i zakończymy jego działanie, wysyłając sygnał przerwania (skrót klawiszowy CTRL+c
):
┌cmd@thinkpad-t480 ~ └> fg %2 ^C⏎ ┌cmd@thinkpad-t480 ~ └> jobs Job Group CPU State Command 1 520 0% running bash -c 'sleep 3600; echo "zadanie1"' &
Na koniec uruchomimy ostatnie działające zadanie jako program pierwszoplanowy i zatrzymamy jego wykonywanie, wysyłając sygnał zatrzymania (skrót klawiszowy CTRL+z
):
┌cmd@thinkpad-t480 ~ └> jobs Job Group CPU State Command 1 520 0% running bash -c 'sleep 3600; echo "zadanie1"' & ┌cmd@thinkpad-t480 ~ └> fg 520 Job 1, “bash -c 'sleep 3600; echo "zada…” has stopped ┌cmd@thinkpad-t480 ~ └> jobs Job Group CPU State Command 1 520 0% stopped bash -c 'sleep 3600; echo "zadanie1"' &
Status programu zmienił się z running
na stopped
. Aby uruchomić ponownie to zadanie w tle, wykorzystamy bg
:
┌cmd@thinkpad-t480 ~ └> bg %1 Send job 1 “bash -c 'sleep 3600; echo "zadanie1"' &” to background ┌cmd@thinkpad-t480 ~ └> jobs Job Group CPU State Command 1 520 0% running bash -c 'sleep 3600; echo "zadanie1"' &
Na koniec zabijemy program komendą kill
:
┌cmd@thinkpad-t480 ~ └> kill 520 ┌cmd@thinkpad-t480 ~ └> jobs jobs: There are no jobs fish: “bash -c 'sleep 3600; echo "zada…” terminated by signal SIGTERM (Polite quit request)
Podsumowanie
W dzisiejszym artykule poznaliśmy, czym są procesy oraz poznaliśmy różnicę między programem a procesem. Poznaliśmy również podstawowe narzędzia do uzyskiwania informacji o stanie procesów w systemie. Wiedza na temat procesów jest kluczowa z punktu widzenia administratora, gdyż zarządzanie systemem odbywa się właśnie poprzez manipulację procesami.