Stany procesów Linuksa

90

Co dzieje się ze stanem procesu w systemie Linux, gdy musi on odczytać bloki z dysku? Czy to jest zablokowane? Jeśli tak, w jaki sposób wybierany jest inny proces do wykonania?

Blair
źródło

Odpowiedzi:

87

Podczas oczekiwania na powrót deskryptora pliku read()lub write()do / z niego, proces zostanie wprowadzony w specjalny rodzaj uśpienia, znany jako „D” lub „Uśpienie dysku”. Jest to szczególne, ponieważ w takim stanie procesu nie można zabić ani przerwać. Proces oczekujący na powrót z ioctl () również zostałby uśpiony w ten sposób.

Wyjątkiem jest sytuacja, gdy plik (taki jak terminal lub inne urządzenie znakowe) jest otwierany w O_NONBLOCKtrybie, przekazywany, gdy zakłada się, że urządzenie (takie jak modem) będzie potrzebowało czasu na zainicjowanie. Jednak w swoim pytaniu wskazałeś urządzenia blokowe. Ponadto, nigdy nie próbowałem ioctl(), aby blokować się na fd otwartym w trybie nieblokującym (przynajmniej nieświadomie).

Sposób wyboru innego procesu zależy całkowicie od używanego harmonogramu, a także od tego, jakie inne procesy mogły zrobić, aby zmodyfikować swoje wagi w tym harmonogramie.

Wiadomo, że niektóre programy przestrzeni użytkownika w pewnych okolicznościach pozostają w tym stanie na zawsze, aż do ponownego uruchomienia. Są one zazwyczaj zgrupowane razem z innymi „zombie”, ale określenie to nie byłoby poprawne, ponieważ nie są one technicznie martwe.

Tim Post
źródło
1
„Proces oczekujący na powrót z ioctl () również zostałby uśpiony w ten sposób”. Właśnie zabiłem proces przestrzeni użytkownika, czekając na blokujący IOCTL, więc to nieprawda. Chyba że nie rozumiem
Hamzahfrq
Byłoby niezwykle trudno zaplanować taki test. Nie można zabić nieprzerywalnych procesów; jeśli byłeś w stanie go zabić, to po prostu blokował (jądro nie znajdowało się w środku żadnej części ioctl i kopiowało odpowiednią odpowiedź do przestrzeni użytkownika w podanej lokalizacji (a przynajmniej nie było w środek kopiowania)). Linux uległ zmianie również wiele od 2009 roku, kiedy to zostało napisane; zjawisko to jest znacznie mniej obserwowalne niż kiedyś.
Tim Post
133

Gdy proces musi pobrać dane z dysku, skutecznie przestaje działać na procesorze, aby umożliwić działanie innym procesom, ponieważ operacja może zająć dużo czasu - co najmniej 5 ms czasu wyszukiwania dysku jest powszechne, a 5 ms to 10 milionów Cykle CPU, wieczność z punktu widzenia programu!

Z punktu widzenia programisty (nazywanego również „w przestrzeni użytkownika”) nazywa się to blokującym wywołaniem systemowym . Jeśli wywołujesz write(2)(co jest cienkim opakowaniem libc wokół wywołania systemowego o tej samej nazwie), twój proces nie zatrzymuje się dokładnie na tej granicy; kontynuuje w jądrze, uruchamiając kod wywołania systemowego. W większości przypadków dochodzi do określonego sterownika kontrolera dysku (nazwa pliku → system plików / VFS → urządzenie blokowe → sterownik urządzenia), gdzie polecenie pobrania bloku z dysku jest wysyłane do odpowiedniego sprzętu, co jest bardzo szybka praca przez większość czasu.

NASTĘPNIE proces przechodzi w stan uśpienia (w przestrzeni jądra blokowanie nazywa się uśpieniem - nic nie jest nigdy „blokowane” z punktu widzenia jądra). Zostanie obudzony, gdy sprzęt w końcu pobierze właściwe dane, a następnie proces zostanie oznaczony jako możliwy do uruchomienia i zostanie zaplanowany. W końcu program planujący uruchomi proces.

Wreszcie, w przestrzeni użytkownika, blokujące wywołanie systemowe wraca z odpowiednim stanem i danymi, a przepływ programu jest kontynuowany.

Jest możliwe, aby wywołać najwięcej I / O wywołań systemowych w trybie non-blocking (patrz O_NONBLOCKw open(2)i fcntl(2)). W takim przypadku wywołania systemowe wracają natychmiast i zgłaszają tylko przesłanie operacji dyskowej. Programista będzie musiał później wyraźnie sprawdzić, czy operacja zakończyła się pomyślnie, czy nie, i pobrać jej wynik (np. Za pomocą select(2)). Nazywa się to programowaniem asynchronicznym lub opartym na zdarzeniach.

Większość odpowiedzi wymieniających stan D (który jest nazywany TASK_UNINTERRUPTIBLEw nazwach stanów Linuksa) jest niepoprawnych. Stan D jest specjalnym trybem uśpienia, który jest wyzwalany tylko w ścieżce kodu przestrzeni jądra, gdy ta ścieżka kodu nie może zostać przerwana (ponieważ byłaby zbyt złożona do zaprogramowania), z oczekiwaniem, że blokowałby się tylko na bardzo krótki czas. Uważam, że większość „stanów D” jest w rzeczywistości niewidocznych; są bardzo krótkotrwałe i nie można ich zaobserwować za pomocą narzędzi do pobierania próbek, takich jak „top”.

W kilku sytuacjach możesz napotkać nieusuwalne procesy w stanie D. NFS słynie z tego i wielokrotnie się z nim spotykałem. Myślę, że istnieje semantyczne zderzenie między niektórymi ścieżkami kodu VFS, które zakładają, że zawsze docierają do dysków lokalnych i szybkie wykrywanie błędów (na SATA, limit czasu błędu wynosiłby około kilku 100 ms), a NFS, który faktycznie pobiera dane z sieci, która jest bardziej odporny i wolno go odzyskuje (często występuje limit czasu TCP wynoszący 300 sekund). Przeczytaj ten artykuł, aby poznać fajne rozwiązanie wprowadzone w Linuksie 2.6.25 ze TASK_KILLABLEstanem. Przed tą erą był hack, w którym można było wysyłać sygnały do ​​klientów procesów NFS, wysyłając SIGKILL do wątku jądra rpciod, ale zapomnij o tej brzydkiej sztuczce.…

zerodeux
źródło
2
+1 za szczegółową odpowiedź, ale pamiętaj, że ten wątek ma akceptowaną odpowiedź od prawie dwóch lat. Kliknij link „Pytania”, jeśli chcesz odpowiedzieć na nowsze pytania. Witamy w Stack Overflow i dziękujemy za Twój wkład!
GargantuChet,
20
Ta odpowiedź jest jedyną, w której wspomina się o NFS, który w niektórych środowiskach jest najczęstszym wyjaśnieniem procesów w stanie D. +1.
Pinko,
14
Bardzo dobra odpowiedź, dzięki. Zauważ również, że proces przechodzi w stan D podczas oczekiwania na strony, które zostały zamienione, więc proces odrzucania będzie w stanie D przez długi czas.
cha0site
@zerodeux dobra odpowiedź, ale myślę, że twój schemat (nazwa pliku -> system plików / VFS -> urządzenie blokowe -> sterownik urządzenia) powinien być (nazwa pliku -> VFS -> system plików (ext3) -> urządzenie blokowe -> sterownik urządzenia)
c4f4t0r
1
Czy byłoby bezpiecznie założyć, że czas spędzony w jądrze na oczekiwaniu na spinlocki (który może, ale nie musi być związany z wejściem / wyjściem dysku), jest raportowany jako stan D /proc/stat?
knot
8

Proces wykonujący operacje we / wy zostanie przełączony w stan D (nieprzerywalny stan uśpienia) , który zwalnia procesor aż do wystąpienia przerwania sprzętowego, które nakazuje procesorowi powrót do wykonywania programu. Zobacz man psinne stany procesu.

W zależności od jądra, istnieje harmonogram procesów , który śledzi kolejkę uruchomieniową procesów gotowych do wykonania. Wraz z algorytmem planowania, informuje jądro, który proces przypisać do którego procesora. Należy wziąć pod uwagę procesy jądra i procesy użytkownika. Każdemu procesowi przydzielany jest przedział czasu, który jest fragmentem czasu procesora, którego może używać. Gdy proces wykorzysta cały swój przedział czasu, jest oznaczany jako wygasły i otrzymuje niższy priorytet w algorytmie planowania.

W jądrze 2.6 istnieje harmonogram złożoności czasowej O (1) , więc bez względu na to, ile procesów masz uruchomionych, przypisuje on procesory w stałym czasie. Jest to jednak bardziej skomplikowane, ponieważ w wersji 2.6 wprowadzono wywłaszczanie, a równoważenie obciążenia procesora nie jest łatwym algorytmem. W każdym razie jest wydajny, a procesory nie pozostaną bezczynne, gdy będziesz czekać na I / O.

user224579
źródło
3

Jak już wyjaśnili inni, procesy w stanie „D” (nieprzerywalny sen) są odpowiedzialne za zawieszenie procesu ps. Dla mnie zdarzyło się to wiele razy w przypadku RedHata 6.xi automatycznie montowanych katalogów domowych NFS.

Aby wyświetlić procesy w stanie D, możesz użyć następujących poleceń:

cd /proc
for i in [0-9]*;do echo -n "$i :";cat $i/status |grep ^State;done|grep D

Aby poznać bieżący katalog procesu i być może zamontowany dysk NFS, na którym występują problemy, możesz użyć polecenia podobnego do poniższego przykładu (zastąp 31134 numerem procesu uśpienia):

# ls -l /proc/31134/cwd
lrwxrwxrwx 1 pippo users 0 Aug  2 16:25 /proc/31134/cwd -> /auto/pippo

Odkryłem, że podanie polecenia umount z przełącznikiem -f (force) do powiązanego zamontowanego systemu plików nfs było w stanie obudzić proces uśpienia:

umount -f /auto/pippo

system plików nie został odmontowany, ponieważ był zajęty, ale powiązany proces się obudził i mogłem rozwiązać problem bez ponownego uruchamiania.

Valerio Di Giampietro
źródło
1

Zakładając, że proces jest pojedynczym wątkiem i używasz blokowania operacji we / wy, proces będzie blokował oczekiwanie na zakończenie operacji we / wy. Jądro wybierze inny proces do uruchomienia w międzyczasie na podstawie uprzejmości, priorytetu, czasu ostatniego uruchomienia itp. Jeśli nie ma innych uruchomionych procesów, jądro nie uruchomi żadnego; zamiast tego poinformuje sprzęt, że maszyna jest bezczynna (co spowoduje mniejsze zużycie energii).

Procesy, które czekają na I / O, aby zakończyć zazwyczaj pojawiają się w państwowej D w, na przykład, psi top.

derobert
źródło
Uruchomiłem kilka procesów wykorzystujących około 10% całkowitej pamięci. Zauważyłem, że wiele z nich jest w stanie D. Czy jest to spowodowane wolnym IO na tym konkretnym komputerze? Powiedzmy, że mam 9 procesów, które mogą konkurować o IO i wiele z nich jest w stanie D.
Kemin Zhou
@KeminZhou W porównaniu z szybkościami procesora I / O jest dość powolne - nawet szybkie I / O. Pojedynczy proces o dużej liczbie operacji we / wy może łatwo zająć dysk magnetyczny, nawet dysk SSD. 10 ciężkich procesów we / wy może być zbyt obciążonych.
derobert
1

Tak, zadanie zostaje zablokowane w wywołaniu systemowym read (). Uruchomione zostanie inne zadanie, które jest gotowe, lub jeśli żadne inne zadania nie są gotowe, zostanie uruchomione zadanie bezczynne (dla tego procesora).

Normalny, blokujący odczyt dysku powoduje przejście zadania w stan „D” (jak zauważyli inni). Takie zadania mają wpływ na średnie obciążenie, mimo że nie zużywają procesora.

Niektóre inne typy IO, szczególnie ttys i network, nie zachowują się tak samo - proces kończy się w stanie „S” i może zostać przerwany i nie jest wliczany do średniej obciążenia.

MarkR
źródło
0

Tak, zadania oczekujące na IO są blokowane, a inne zadania są wykonywane. Wyboru następnego zadania dokonuje program planujący Linuksa .

Martin przeciwko Löwis
źródło
0

Ogólnie proces będzie się blokował. Jeśli operacja odczytu znajduje się na deskryptorze pliku oznaczonym jako nieblokujący lub jeśli proces używa asynchronicznych operacji we / wy, nie zostanie zablokowany. Jeśli proces ma inne wątki, które nie są zablokowane, mogą kontynuować działanie.

Decyzja o tym, który proces zostanie uruchomiony jako następny, należy do programu planującego w jądrze.

Benno
źródło