Interfejs uzytkownika - procesy
ŁF
LINUX - Interfejs użytkownika.
2. PROCESY
</span> Każdy system operacyjny ma do spełnienia dwa podstawowe cele:- efektywne zarządzanie zasobami systemu komputerowego,
- zapewnienie wygodnej pracy użytkownikom.
- manipulowanie plikami,
- edycja i przetwarzanie plików,
- tworzenie i wykonywanie programów,
- komunikację sieciową,
- informowanie o stanie systemu.
Jedną z podstawowych usług świadczonych przez system na rzecz użytkowników jest wykonywanie programów. Wykonujący się program nosi nazwę procesu. Poniżej przybliżamy pojęcia procesu, grupy współpracujących procesów oraz sesji procesów korzystających ze wspólnego terminala sterującego. Przedstawiamy metody uruchamiania procesów oraz wpływu na przebieg ich wykonania poprzez zmianę priorytetu i przesyłanie sygnałów. Omawiamy również sterowanie pracami przez interpreter poleceń, umożliwiające wybiórcze wstrzymywanie i wznawianie działających procesów.
Procesy
</span>Jedną z podstawowych usług każdego systemu operacyjnego jest wykonywanie programów. Program to zbiór instrukcji dla procesora przechowywany na dysku w postaci pliku. Przed uruchomieniem programu jądro systemu musi przydzielić odpowiednie zasoby systemowe i utworzyć środowisko, w którym program będzie wykonany. Takie środowisko wykonania programu określa się mianem procesu.
Proces to wykonujący się program.
W odróżnieniu od programu, proces jest obiektem aktywnym. Proces pełni rolę podstawowej jednostki pracy systemu operacyjnego.
(1.1) Procesy, grupy i sesje
W systemie Linux nowy proces może być utworzony wyłącznie z inicjatywy innego procesu (jedyny wyjątek od tej reguły opisano w punkcie 1.4). Techniczną stroną operacji zajmuje się jądro systemu, ale działa ono jedynie na zlecenie innego procesu. Dlatego powszechnie określa się, że to proces macierzysty (rodzic) tworzy proces potomny (potomka). Potomek jest tworzony jako kopia rodzica: dziedziczy po nim większość atrybutów oraz otrzymuje kopię jego zasobów systemowych, a niektóre z nich może nawet współdzielić. Od tej chwili obydwa procesy działają niezależnie. Proces macierzysty może nadzorować wykonywanie swoich procesów potomnych. Jądro informuje go o zakończeniu każdego z potomków. Może wtedy odebrać kod wyjścia potomka przechowywany przez jądro. Jeżeli rodzic kończy działanie wcześniej, to osierocone procesy potomne są adoptowane przez proces init.
W celu ułatwienia zarządzania procesy organizowane są przez system w sesje. Do każdej sesji przypisany jest terminal sterujący, który procesy wykorzystują do pobierania danych wejściowych i wysyłania wyników. Proces, który utworzył sesję zostaje jej przywódcą (liderem). Zazwyczaj jest to proces interpretera poleceń. Wszyscy jego potomkowie pozostają członkami sesji, dopóki nie zdecydują się zainicjować nowej sesji.
W ramach jednej sesji może powstać wiele grup współpracujących procesów. Tworzenie grup umożliwia systemowi utrzymywanie informacji o tym, które procesy współpracują ze sobą. Proces, który założył nową grupę zostaje jej przywódcą, a jego procesy potomne dziedziczą członkostwo w grupie. Procesy mogą dowolnie zmieniać przynależność do grupy w ramach jednej sesji. Wszystkie procesy w danej grupie muszą jednak należeć do tej samej sesji.
(1.2) Atrybuty procesu
Jądro systemu przechowuje informacje o wszystkich aktywnych procesach. Zapisane są tam atrybuty każdego procesu takie, jak:
- identyfikator procesu PID,
- identyfikator procesu macierzystego,
- identyfikatory grupy procesów i sesji,
- identyfikator właściciela procesu,
- stan procesu,
- priorytet procesu .
Każdy działający proces jest jednoznacznie określony przez swój unikalny identyfikator PID. Proces przechowuje też identyfikator procesu, który go utworzył, czyli swojego procesu macierzystego (rodzica), jak również identyfikatory grupy i sesji, do których należy. Identyfikator właściciela decyduje o uprawnieniach procesu. Wszystkie identyfikatory są nieujemnymi liczbami całkowitymi. Proces w systemie Linux może znaleźć się w jednym z pięciu stanów, których listę przedstawiono w Tablicy 1.1.
<font size="+1">Tablica 2.1. </span><font size="+1">Stany procesu w systemie Linux.</span>
</caption> Działający(TASK_RUNNING)</td> Proces gotowy do wykonania lub wykonywany przez procesor.</td> </tr> Uśpiony przerywalny
(TASK_INTERRUPTIBLE)</td> Proces uśpiony w oczekiwaniu na jakieś zdarzenie (np. zakończenie operacji wejścia/wyjścia) z możliwością obudzenia sygnałem.</td> </tr> Uśpiony nieprzerywalny
(TASK_UNINTERRUPTIBLE</td> Proces uśpiony w oczekiwaniu na jakieś zdarzenie bez możliwości obudzenia sygnałem.</td> </tr> Zombie
(TASK_ZOMBIE)</td> Proces został zakończony, ale jądro wciąż przechowuje informacje dla procesu macierzystego.</td> </tr> Zatrzymany
(TASK_STOPPED)</td> Proces zatrzymany w wyniku śledzenia wykonania lub w wyniku odebrania sygnału.</td> </tr> </table>
Priorytet procesu decyduje o kolejności przydziału czasu procesora, a w konsekwencji o kolejności wykonania poszczególnych procesów. Przyjmuje wartości całkowite, nieujemne. W większości systemów operacyjnych, również w systemie Linux, przyjęto konwencję, że mniejsza wartość liczbowa oznacza wyższy priorytet.
(1.3) Informacje o procesach
Polecenie ps umożliwia wyświetlenie listy procesów uruchomionych w systemie i obejrzenie ich atrybutów. Oto jego składnia:
ps [opcje]
Wywołane bez opcji, polecenie ps wyświetla listę procesów z bieżącej sesji (związanych z bieżącym terminalem sterującym). Podawana informacja obejmuje identyfikator procesu, identyfikator terminala sterującego, skumulowany czas wykonywania procesu oraz nazwę programu, który proces wykonuje. Dobierając odpowiednie opcje możemy sterować zarówno wyborem wyświetlanych procesów, jak i zakresem podawanych informacji. Poniżej przedstawiamy znaczenie wybranych opcji. Pełny wykaz można uzyskać wydając polecenie man ps.Opcje wyboru procesów:
-a | - | wszystkie procesy związane z jakimś terminalem sterującym, |
-e, -A | - | wszystkie procesy, |
-u ident_użytk. | - | wszystkie procesy wskazanego użytkownika, |
-t tty | - | wszystkie procesy związane z wskazanym przez argument tty terminalem sterującym, |
-p PID | - | proces o podanym numerze PID. |
Opcje zakresu informacji:
-f | - | format pełny, |
-l | - | format długi, |
-j | - | format zorientowany na prace, |
-s | - | format zorientowany na sygnały, |
-o | - | format format zdefiniowany przez użytkownika. |
Polecenie ps wypisuje żądane informacje w układzie kolumnowym. Kategorie tych informacji są przedstawione w tablicy 2.2:
Przykład.
Wydanie polecenia ps -fu root spowoduje wyświetlenie wszystkich procesów użytkownika root, czyli większości procesów systemowych (Rys.2.1).
Rys 2.1 Przykładowy wynik działania polecenia ps -fu root |
Listę aktywnych procesów można również uzyskać przy pomocy polecenia pstree. Wyświetla ono informacje w postaci drzewa uwzględniając powiązania rodzinne między procesami (rys.2.2).
|
Rys 2.2 Przykładowy wynik działania polecenia pstree |
Polecenie top szereguje wyświetlane procesy według stopnia wykorzystania zasobów systemowych, na bieżącą aktualizując informacje (rys.2.3).
Rys 2.3 Przykładowy wynik działania polecenia top |
(1.4) Przegląd procesów systemowych
W chwili STARTu systemu Linux tworzony jest proces INIT_TASK o numerze PID=0. Jest to jedyny proces tworzony przez jądro systemu, a nie przez inny proces. Jego jedynym zadaniem jest utworzenie procesu init o numerze PID=1. Proces INIT_TASK nigdy nie pojawia się na liście wyświetlanych procesów.
W innych systemach uniksowych proces o PID=0 otrzymuje również inne zadanie i jest uwzględniany na liście aktywnych procesów pod nazwą sched lub swapper.
Proces init uruchamia pozostałe procesy systemowe zgodnie z zawartością odpowiednich plików konfiguracyjnych (m.in. pliku /etc/inittab). Procesy utworzone przez init'a pełnią rolę serwerów różnych usług systemowych i noszą nazwę demonów, np.:
- syslogd (demon przechowywania komunikatów systemowych),
- klogd (demon przechowywania komunikatów jądra),
- lockd (demon zajmowania plików i rekordów),
- crond (demon zegarowy),
- inetd (demon internetowy, który na żądanie uruchamia poszczególne usługi sieciowe, czyli uruchamia odpowiednie demony),
- sendmail (demon poczty elektronicznej).
Demony nie mają terminala sterującego i przez większość czasu pozostają uśpione w oczekiwaniu na wystąpienie żądania udostępnienia danej usługi.
(1.5) Procesy związane z sesją użytkownika
W otwarcie tekstowej sesji użytkownika zaangażowane są tylko 3 procesy:
- getty,
- login,
- bash (lub inny interpreter poleceń, np. sh, tcsh ) .
Proces getty to proces obsługi terminala. Określa on parametry początkowe linii terminala i oczekuje na zgłoszenie użytkownika po czym uruchamia proces login.
Proces login to proces autoryzacji użytkowników. Jego rola polega na pobraniu nazwy i hasła użytkownika, dokonania autoryzacji a po jej pomyślnym zakończeniu uruchomieniu procesu interpretera poleceń np. sh, csh, bash, tcsh, zsh.
Sesja graficzna wymaga dodatkowo uruchomienia wielu innych procesów, a w szczególności serwera systemu X Window (np. XFree86), menedżera okien (np. fvwm2) oraz najczęściej systemu aktywnego pulpitu (np. KDE lub GNOME).
(1.6) Uruchamianie procesów
Użytkownik może uruchomić nowy proces na 2 sposoby:
- wydając odpowiednie polecenie powłoce,
- wywołując program w środowisku graficznym (przez wybranie odpowiedniej pozycji z menu lub przyciśnięcie ikony programu).
Wywołując program w powłoce można uruchomić proces na pierwszym planie (ang. foreground) lub w tle, czyli na drugim planie (ang. background).
Proces pierwszoplanowy jest uprzywilejowany w dostępie do terminala sterującego, może pobierać dane z terminala i wypisywać wyniki. Do momentu zakończenia procesu nie można wydawać powłoce żadnych poleceń.
Proces drugoplanowy nie może komunikować się z terminalem. Sterowanie powraca do procesu powłoki, dzięki czemu można wydawać kolejne polecenia.
Proces pierwszoplanowy uruchamia się przez podanie w powłoce nazwy polecenia z argumentami:
polecenie arg1 arg2 arg3 ...
np.: ps -fu root
W celu uruchomienia procesu w tle należy zakończyć polecenie znakiem &:
polecenie arg1 ... &
np.: netscape &
Interpreter poleceń umożliwia także jednoczesne uruchomienie grupy współpracujących procesów, tworzących potok:
polecenie1 | polecenie2 | polecenie3 ...
np.: ps -ef | more
Każdy z tych procesów przesyła swoje dane wyjściowe do następnego procesu w potoku zamiast do terminala sterującego. W podanym przykładzie lista procesów wyprodukowana przez ps zostaje przesłana do procesu more, który wyświetla ją strona po stronie.
W przypadku przerwania połączenia z terminalem sterującym (w wyniku zakończenia sesji użytkownika lub zerwania łączności fizycznej) system usiłuje zakończyć wszystkie procesy z sesji związanej z terminalem, wysyłając sygnał SIGHUP (patrz SEGMENT 2 w tej lekcji). Zapobiega to pozostawaniu niepotrzebnych procesów w systemie po wylogowaniu użytkownika. Istnieje jednak możliwość świadomego pozostawienia procesu działającego po zakończeniu sesji w celu wykonania jakichś operacji (np. długotrwałych obliczeń, zdalnego kopiowania dużych plików):
nohup polecenie arg ... [&]
Polecenie nohup uruchamia proces w taki sposób że ignoruje on sygnał SIGHUP oraz kieruje wyjście procesu do pliku nohup.out zamiast na terminal. Takie procesy uruchamiane są zwykle uruchamiane w tle.
(1.7) Zmiana priorytetu procesu
Użytkownik nie może ustawić bezpośrednio wartości priorytetu procesu. Bieżąca wartość priorytetu obliczana jest na podstawie wartości parametru nice oraz czasu wykorzystywania procesora. Wartość parametru nice określa stopień "uprzejmości" procesu wobec innych procesów i przyjmuje wartość początkową 0. Zwiększanie tej wartości powoduje obniżanie priorytetu.
Zwykły użytkownik może jedynie obniżyć priorytet własnych procesów zwiększając wartości parametru nice.
Polecenie nice umożliwia uruchomienie nowego procesu z obniżonym priorytetem:
nice [-zmiana] polecenie [arg ...]
Argument zmiana przyjmuje wartości z przedziału <-20, 19> i określa zmianę wartości parametru nice dla procesu. Zwykły użytkownik może użyć wartości argumentu zmiana z przedziału <0, 19>, pełen zakres wartości dostępny jest tylko dla administratora.
Możliwa jest również zmiana priorytetu działającego już procesu za pomocą polecenia renice:
renice wartość [[-p] pid ...] [[-g] pgrp ...] [[-u] użytkownik ...]
Polecenie renice ustawia nową wartość parametru nice z przedziału <-20, 19> dla procesów specyfikowanych przez:
- identyfikator pid,
- identyfikator grupy procesów pgrp,
- nazwę użytkownika będącego właścicielem procesów.
W dziale źródła/C++ znajdują się przykładowe programy do tego i pozostałych artykułów z tego cyklu.
Wszelkie pytania proszę kierować na adres L.Fronczyk@elka.pw.edu.pl