Blog » Linux

Procesy w systemach GNU/Linux

Linux procesy

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 z pid=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ę:

[email protected] ~
└> 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żytkownika
  • u – wyświetlanie w sposób bardziej przyjazny użytkownikowi
  • x – wyświetla wszystkie procesy, niezależnie od tego, do jakiego wirtualnego terminala są podpięte.
[email protected] ~
└> 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:

 

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.

[email protected] ~
└> 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:

[email protected] ~
└> pidof firefox
26373
┌[email protected] ~
└> 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:

  1. jobs – wyświetla obecnie uruchomione w powłoce zadania/procesy
  2. bg [PID] (ang. background) – uruchamia proces o podanym pid w tle
  3. fg [PID] (ang. foreground) – uruchamia proces o podanym pid 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.

[email protected] ~
└> bash -c 'sleep 3600; echo "zadanie1"' &
┌[email protected] ~
└> bash -c 'sleep 3600; echo "zadanie2"' &
┌[email protected] ~
└> bash -c 'sleep 10; echo "zadanie3"' &
┌[email protected] ~
└> 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”:

[email protected] ~
└> zadanie3
Job 3, “bash -c 'sleep 10; echo "zadani…” has ended
┌[email protected] ~
└> 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):

[email protected] ~
└> fg %2 
^C⏎
┌[email protected] ~
└> 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):

[email protected] ~
└> jobs
Job Group   CPU State   Command
1   520 0%  running bash -c 'sleep 3600; echo "zadanie1"' &
┌[email protected] ~
└> fg 520
Job 1, “bash -c 'sleep 3600; echo "zada…” has stopped
┌[email protected] ~
└> 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:

[email protected] ~
└> bg %1
Send job 1 “bash -c 'sleep 3600; echo "zadanie1"' &” to background
┌[email protected] ~
└> jobs
Job Group   CPU State   Command
1   520 0%  running bash -c 'sleep 3600; echo "zadanie1"' &

Na koniec zabijemy program komendą kill:

[email protected] ~
└> kill 520
┌[email protected] ~
└> 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.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *