2009-09-25 2 views
74

В Linux, что происходит с состоянием процесса, когда ему нужно читать блоки с диска? Он заблокирован? Если да, то каким образом выбран другой процесс?Состояние процесса Linux

ответ

70

Ожидая read() или write() в/из возврата дескриптора файла, процесс будет помещен в особый вид сна, известный как «D» или «Диск сна». Это особенное, потому что процесс не может быть убит или прерван в таком состоянии. Таким образом, процесс, ожидающий возвращения из ioctl(), также будет усыпан.

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

Как выбрать другой процесс, зависит только от планировщика, который вы используете, а также от того, что другие процессы могли бы сделать, чтобы изменить их веса в этом планировщике.

Некоторые программы пользовательского пространства при определенных обстоятельствах, как известно, остаются в этом состоянии навсегда, до перезагрузки. Они обычно группируются вместе с другими «зомби», но этот термин не будет правильным, поскольку они не являются технически несуществующими.

+1

«Процесс, ожидающий возвращения из ioctl(), также будет усыпан таким образом». Я просто убил мой процесс пользовательского пространства, ожидая блокировки IOCTL, так что это неверно. Если я не пропущу – Hamzahfrq

+0

Было бы непросто провести такой тест. Непрерывные процессы не могут быть убиты; если вы смогли его убить, тогда он просто блокировался (ядро не было посередине любой части ioctl и копировало любой соответствующий ответ на пользовательское пространство в том месте, где вы проходили (или, по крайней мере, не находилось в середина копирования)). Linux также изменился _a lot_ с 2009 года, когда это было написано; феномен гораздо менее заметен, как когда-то. –

1

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

Процессы, ожидающие завершения ввода-вывода, обычно отображаются в состоянии D, например, ps и top.

+0

Я запустил несколько процессов, используя около 10% от общей памяти. Я заметил, что многие из них находятся в состоянии D. Это связано с медленным IO на этой конкретной машине? Скажем, у меня есть 9 процессов, они могут конкурировать за IO, и многие из них находятся в состоянии D. –

+0

@KeminZhou По сравнению со скоростью процессора, I/O довольно медленный, даже быстрый ввод-вывод. Один тяжелый процесс ввода-вывода может легко заняться магнитным диском, даже SSD. 10 Тяжелые процессы ввода-вывода могут быть заняты немало. – derobert

0

Да, задачи, ожидающие ввода-вывода, блокируются и выполняются другие задачи. Выбор следующей задачи осуществляется с помощью Linux scheduler.

0

Как правило, процесс блокируется. Если операция чтения находится в файловом дескрипторе, помеченном как неблокирующее, или если процесс использует асинхронный ввод-вывод, он не будет блокироваться. Кроме того, если в процессе есть другие потоки, которые не блокируются, они могут продолжать работать.

Решение о том, какой процесс проходит дальше, зависит от scheduler в ядре.

6

Процесс, выполняющий ввод-вывод, будет помещен в D состояние (бесперебойный сон), который освобождает процессор до тех пор, пока не произойдет аппаратное прерывание, которое сообщает CPU о возврате к выполнению программы. См. man ps для других состояний процесса.

В зависимости от вашего ядра есть планировщик процессов , который отслеживает запуск готовых процессов. Он, наряду с алгоритмом планирования, сообщает ядру, который обрабатывает, чтобы назначить на какой процессор. Процессы ядра и пользовательские процессы необходимо учитывать. Каждому процессу выделяется срез времени, который является куском времени процессора, которое разрешено использовать. Как только процесс использует весь свой временной срез, он помечается как истек и получает более низкий приоритет в алгоритме планирования.

В 2.6 ядро ​​, есть O (1) планировщик сложности времени, поэтому независимо от того, сколько процессов у вас запущено, он будет назначать процессоры в постоянное время. Однако это сложнее, так как в 2.6 введена предварительная настройка и балансировка загрузки процессора - это не простой алгоритм. В любом случае, он эффективен, и процессоры не будут оставаться в режиме ожидания, пока вы ждете ввода-вывода.

1

Да, задача блокируется при системном вызове read(). Другая задача, которая готова к запуску или если другие задачи не готовы, запускается незанятая задача (для этого ЦП).

Нормальное считывание блокирующего диска заставляет задачу войти в состояние «D» (как отмечали другие). Такие задачи способствуют усреднению нагрузки, даже если они не потребляют процессор.

Некоторые другие типы ввода-вывода, особенно ttys и network, не ведут себя совершенно одинаково - процесс заканчивается в состоянии «S» и может быть прерван и не учитывается при средней нагрузке.

112

Когда процесс должен извлекать данные с диска, он фактически перестает работать на ЦПУ, чтобы другие процессы выполнялись, потому что операция могла занять много времени - обычно требуется не менее 5 мс времени поиска для диска, и 5 мс - это 10 миллионов циклов процессора, вечность с точки зрения программы!

С точки зрения программиста (также сказано «в пользовательском пространстве») это называется системным вызовом . Если вы вызываете write(2) (который представляет собой тонкую оболочку libc вокруг системного вызова с тем же именем), ваш процесс точно не останавливается на этой границе: он продолжает, со стороны ядра, запускать код системного вызова. Большую часть времени он проходит вплоть до конкретного драйвера контроллера диска (имя файла → файловая система/VFS → блок устройства → драйвер устройства), где команда для извлечения блока на диске представляется на надлежащее оборудование: это очень быстрая работа большую часть времени.

THEN процесс помещается в состояние ожидания (в пространстве ядра блокировка называется спящим - ничто никогда не блокируется с точки зрения ядра). Он снова проснется после того, как аппаратное обеспечение наконец вернет правильные данные, тогда процесс будет отмечен как runnable, запланированный и запущенный, как только планировщик это разрешит.

Наконец, в пользовательском пространстве системный вызов блокировки возвращается с соответствующим статусом и данными, а поток программы продолжается.

можно вызвать большую систему ввода/вывода вызывает в неблокирующая режим (см O_NONBLOCK в open(2) и fcntl(2)). В этом случае система немедленно вызывает возврат и сообщает только о правильной передаче операции с диском. Программист должен будет явно проверить позднее, если операция завершена с успехом или нет и извлечет ее результат (например, с помощью select(2)). Это называется асинхронным или основанным на событиях программированием.

Большинство ответов здесь, в которых упоминается состояние D, (точное имя TASK_UNINTERRUPTIBLE от имени Linux) неверны. Состояние D - это особый режим ожидания, который запускается только в коде кода ядра, когда этот путь кода не может быть прерван (поскольку это было бы сложно запрограммировать), большую часть времени в надежде что он будет блокироваться очень скоро. Я считаю, что большинство «D-состояний» фактически невидимы, они очень недолговечны и не могут быть замечены инструментами выборки, такими как «верх».

Но вы можете столкнуться с этими неудобными процессами в состоянии D в нескольких ситуациях. NFS славится этим, и я сталкивался с ним много раз. Я думаю, что существует семантическое столкновение между некоторыми кодами путей VFS, которые предполагают, что они всегда достигают локальных дисков и быстрого обнаружения ошибок (на SATA, время ожидания составляет около 100 мс) и NFS, которая фактически извлекает данные из сети, которая больше устойчив и имеет медленное восстановление (общий тайм-аут TCP составляет 300 секунд). Прочитайте this article для прохладного решения, представленного в Linux 2.6.25 с состоянием TASK_KILLABLE. До этой эры был взлом, в котором вы могли отправлять сигналы клиентам процессов NFS, отправив SIGKILL в поток ядра rpciod, но забудьте об этом уродливом трюке & hellip;

+2

+1 для подробного ответа, но учтите, что эта тема получила принятый ответ в течение почти двух лет. Нажмите ссылку «Вопросы», если вы хотите протянуть руку по более поздним вопросам. Добро пожаловать в Stack Overflow и спасибо за вклад! – GargantuChet

+17

Этот ответ является единственным, кто упомянет NFS, который в некоторых средах является наиболее распространенным объяснением процессов в состоянии D. +1. – Pinko

+12

Очень хороший ответ, спасибо. Также обратите внимание, что процесс переходит в состояние D в ожидании страниц, которые были выгружены, поэтому процесс перемотки будет находиться в состоянии D в течение длительного времени. – cha0site

2

Как уже объяснялось другими, процессы в состоянии «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 

Я обнаружил, что давая размонтировать команду с -f (сила) переключатель, чтобы связанная с этим установлен Nfs файловой системы, был в состоянии Wake- вверх по процессу сна:

umount -f /auto/pippo 

Файловая система не была размонтирована, поскольку она была занята, но связанный с ней процесс просыпался, и я смог решить проблему без перезагрузки.

Смежные вопросы