Стани процесу Linux


90

Що в Linux відбувається зі станом процесу, коли йому потрібно зчитувати блоки з диска? Це заблоковано? Якщо так, то як обраний інший процес для виконання?

Відповіді:


87

В очікуванні на read()абоwrite() повернення дескриптора файлу з / до нього процес буде переведено в спеціальний тип сну, відомий як "D" або "Дисковий режим сну". Це особливе, оскільки процес не може бути вбитий або перерваний, перебуваючи в такому стані. Процес, який чекає повернення з ioctl (), також буде призупинено таким чином.

Виняток з цього полягає у тому, коли файл (наприклад, термінал чи інший символьний пристрій) відкривається в O_NONBLOCKрежимі, передається тоді, коли передбачається, що пристрою (наприклад, модему) знадобиться час для ініціалізації. Однак у своєму запитанні ви вказали блокуючі пристрої. Крім того, я ніколи не пробував, ioctl()що, ймовірно, може заблокувати fd, відкритий у неблокуючому режимі (принаймні не свідомо).

Вибір іншого процесу повністю залежить від планувальника, який ви використовуєте, а також від того, що інші процеси могли б зробити, щоб змінити свою вагу в межах цього планувальника.

Відомо, що деякі програми користувацького простору за певних обставин залишаються у такому стані назавжди, доки їх не перезавантажать. Вони, як правило, об’єднуються з іншими „зомбі”, але цей термін не буде правильним, оскільки вони технічно не існують.


1
"Процес, який очікує повернення з ioctl (), також буде призупинено таким чином". Я просто вбив свій процес користувацького простору, чекаючи блокування IOCTL, тому це неправда. Якщо я не
зрозумію неправильно

Було б надзвичайно важко встановити такий тест. Безперебійні процеси не можна вбивати; якщо ви змогли його вбити, то це просто блокувало (ядро не було посередині жодної частини ioctl і скопіювало будь-яку відповідну відповідь у користувацький простір у пройденому вами місці (або, принаймні, не було в середина копіювання)). Linux також змінився багато з 2009 року , коли це було написано; явище набагато менш спостережуване, як це було колись.
Tim Post

133

Коли процесу потрібно отримати дані з диска, він фактично перестає запускатися на центральному процесорі, щоб дозволити іншим процесам запускатися, оскільки операція може зайняти багато часу - принаймні 5 мс шукає час для диска, а 5 мс - це 10 мільйонів Цикли процесора, вічність з точки зору програми!

З точки зору програміста (це також називається "в просторі користувачів"), це називається системним викликом блокування . Якщо ви зателефонуєте write(2)(це тонка обгортка libc навколо однойменного системного виклику), ваш процес точно не зупиняється на цій межі; він продовжує в ядрі виконувати код системного виклику. Велику частину часу він проходить весь шлях до певного драйвера контролера диска (ім'я файлу → файлова система / VFS → блокувати пристрій → драйвер пристрою), де команда для отримання блоку на диску подається до відповідного обладнання, що є дуже швидке функціонування більшу частину часу.

ПОТІМ процес переходить у сплячий стан (у просторі ядра блокування називається сплячим - нічого ніколи не «блокується» з точки зору ядра). Він буде пробуджений після того, як обладнання остаточно отримає належні дані, тоді процес буде позначений як запущений і буде запланований. Згодом планувальник запустить процес.

Нарешті, в просторі користувачів блокуючий системний виклик повертається з належним статусом і даними, і потік програми продовжується.

Можна викликати більшість системних викликів вводу-виводу в неблокуючому режимі (див. O_NONBLOCKВ open(2)та fcntl(2)). У цьому випадку системні виклики повертаються негайно і повідомляють лише про передачу операції диска. Програмісту доведеться явно перевірити пізніше, чи завершена операція успішно чи ні, і отримати її результат (наприклад, за допомогою select(2)). Це називається асинхронним або заснованим на подіях програмуванням.

Більшість відповідей тут, де згадується стан D (що називається TASK_UNINTERRUPTIBLEв іменах стану Linux), є неправильними. Стан D - це спеціальний режим сну, який запускається лише в коді простору ядра, коли цей шлях коду не може бути перерваний (оскільки він буде занадто складним для програмування), з очікуванням, що він заблокує лише дуже короткий час. Я вважаю, що більшість "станів D" насправді невидимі; вони дуже короткочасні, і їх неможливо спостерігати за допомогою інструментів для відбору проб, таких як „верх”.

Ви можете зіткнутися з невдалими процесами в стані D у декількох ситуаціях. NFS цим славиться, і я вже неодноразово стикався з цим. Я думаю, є семантичне зіткнення між деякими шляхами коду VFS, які передбачають, що завжди досягають локальних дисків і швидке виявлення помилок (на SATA час очікування помилок становить близько 100 мс), і NFS, який фактично отримує дані з мережі, яка є більш еластичним і має повільне відновлення (частота очікування TCP становить 300 секунд). Прочитайте цю статтю про круте рішення, представлене в Linux 2.6.25 із TASK_KILLABLEстаном. До цієї епохи був хак, коли ви могли фактично надсилати сигнали клієнтам процесів NFS, надсилаючи SIGKILL в потік ядра rpciod, але забути про цей потворний трюк ...


2
+1 для детальної відповіді, але зауважте, що ця тема вже два роки приймає відповідь. Натисніть посилання "Запитання", якщо ви хочете допомогти останнім питанням. Ласкаво просимо до Stack Overflow та дякуємо за внесок!
GargantuChet

20
Ця відповідь є єдиною, на яку згадується NFS, яка в деяких середовищах є найпоширенішим поясненням процесів у стані D. +1.
Пінько

14
Дуже хороша відповідь, дякую. Також зауважте, що процес переходить у стан D під час очікування сторінок, які були замінені, тому процес обробки буде тривалий час знаходитись у стані D.
cha0site

@zerodeux хороша відповідь, але я думаю, що ваша схема (ім'я файлу -> файлова система / VFS -> блок пристрою -> драйвер пристрою) повинна бути (ім'я файлу -> VFS -> файлова система (ext3) -> блок пристрою -> драйвер пристрою)
c4f4t0r

1
Чи можна було б припустити, що час, проведений в ядрі в очікуванні на спінлоки (який може бути пов’язаний із введенням / виводом диска) може відображатися як D-стан /proc/stat?
фітиль

8

Процес, що виконує введення-виведення, буде переведений у стан D (безперебійний режим сну) , що звільняє центральний процесор, поки не відбудеться апаратне переривання, яке повідомляє центральному процесору повернутися до виконання програми. Дивіться man psінші стани процесу.

Залежно від вашого ядра, існує планувальник процесів , який відслідковує чергу виконання процесів, готових до виконання. Він разом з алгоритмом планування повідомляє ядру, який процес призначити якому ЦП. Існують процеси ядра та процеси користувача, які слід враховувати. Кожному процесу присвоюється часовий зріз, який становить частину процесорного часу, яку йому дозволено використовувати. Як тільки процес використовує весь свій часовий зріз, він позначається як закінчився і надається нижчий пріоритет в алгоритмі планування.

У ядрі 2.6 існує планувальник складності часу O (1) , тому незалежно від того, скільки процесів у вас запущено, він призначатиме процесори за постійний час. Однак це складніше, оскільки введене попередження 2.6 та балансування навантаження процесора - непростий алгоритм. У будь-якому випадку, це ефективно, і процесори не залишатимуться в режимі очікування, поки ви чекаєте введення-виведення.


3

Як вже пояснювали інші, процеси у стані "D" (безперебійний сон) відповідають за зависання процесу ps. У мене це траплялося багато разів із RedHat 6.x та автоматичними домашніми каталогами NFS.

Для переліку процесів у стані D ви можете використовувати такі команди:

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

Щоб знати поточний каталог процесу та, можливо, змонтований диск NFS, який має проблеми, ви можете скористатися командою, подібною до наступного прикладу (замініть 31134 на номер процесу сну):

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

Я виявив, що надання команди umount за допомогою перемикача -f (force) відповідній змонтованій файловій системі nfs змогло активувати процес сну:

umount -f /auto/pippo

файлову систему не демонтували, оскільки вона була зайнята, але пов'язаний з цим процес прокинувся, і я зміг вирішити проблему без перезавантаження.


1

Припускаючи, що ваш процес є єдиним потоком, і що ви використовуєте блокування вводу-виводу, ваш процес заблокує очікування завершення вводу-виводу. Ядро вибере інший процес, який тим часом буде запущений, виходячи зі слабкості, пріоритету, часу останнього запуску і т. Д. Якщо інших запущених процесів немає, ядро ​​не запускатиме жодного; натомість він повідомляє апаратному забезпеченню, що машина не працює (що призведе до зниження енергоспоживання).

Процеси, які очікують завершення вводу-виводу, зазвичай відображаються у стані D у, наприклад, psі top.


Я запустив кілька процесів, використовуючи близько 10% загальної пам'яті. Я помітив, що багато з них перебувають у штаті D. Це пов’язано з повільним введенням-виведенням на цій машині? Скажімо, у мене 9 процесів, вони можуть конкурувати за введення-виведення, і багато з них перебувають у стані D.
Кемін Чжоу

@KeminZhou Порівняно зі швидкістю процесора, введення / виведення досить повільне - навіть швидке введення / виведення. Один важкий процес введення-виведення може легко зайняти магнітний диск, навіть твердотільний диск. 10 важких процесів вводу-виводу може зайняти чимало.
derobert

1

Так, завдання блокується під час системного виклику read (). Виконується інше готове завдання, або якщо жодне інше завдання не готове, виконується неактивне завдання (для цього процесора).

Звичайне блокування читання диска призводить до того, що завдання переходить у стан "D" (як зазначали інші). Такі завдання сприяють середньому навантаженню, навіть якщо вони не споживають центральний процесор.

Деякі інші типи вводу-виводу, особливо ttys та мережа, поводяться не зовсім однаково - процес закінчується у стані "S" і може бути перерваний і не враховується в середньому навантаженні.



0

Як правило, процес блокується. Якщо операція зчитування виконується в дескрипторі файлу, позначеному як неблокуючий, або якщо процес використовує асинхронний введення-виведення, він не блокується. Також якщо в процесі є інші потоки, які не заблоковані, вони можуть продовжувати працювати.

Рішення щодо подальшого запуску процесу залежить від планувальника в ядрі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.