В Linux, что происходит с состоянием процесса, когда ему нужно читать блоки с диска? Он заблокирован? Если да, то как выполняется другой процесс?
Linux-процессы
Ответ 1
Ожидая read()
или write()
в/из возврата дескриптора файла, процесс будет помещен в особый вид сна, называемый "D" или "Диск сна". Это особенное, потому что процесс не может быть убит или прерван в таком состоянии. Этот процесс, ожидающий возвращения из ioctl(), также будет усыпан таким образом.
Исключением является то, что файл (например, терминал или другое символьное устройство) открывается в режиме O_NONBLOCK
, передается, когда предполагается, что устройству (например, модему) потребуется время для инициализации. Однако в вашем вопросе вы указали блокирующие устройства. Кроме того, я никогда не пробовал ioctl()
, который, вероятно, блокирует fd, открытый в неблокирующем режиме (по крайней мере, не сознательно).
Выбор другого процесса зависит полностью от используемого планировщика, а также от того, что другие процессы могли бы сделать, чтобы изменить их веса в этом планировщике.
Некоторые программы пользовательского пространства при определенных обстоятельствах, как известно, остаются в этом состоянии навсегда, до перезагрузки. Они обычно группируются вместе с другими "зомби", но этот термин не будет правильным, поскольку они не являются технически несуществующими.
Ответ 2
Когда процессу необходимо извлечь данные с диска, он фактически прекращает работу на ЦП, чтобы позволить другим процессам выполняться, потому что операция может занять много времени - обычное время поиска диска не менее 5 мс, а 5 мс - 10 млн. Циклы процессора, вечность с точки зрения программы!
С точки зрения программиста (также называемого "в пространстве пользователя"), это называется системным вызовом блокировки. Если вы вызываете write(2)
(которая является тонкой оболочкой libc для системного вызова с тем же именем), ваш процесс точно не останавливается на этой границе; в ядре он продолжает выполнять код системного вызова. Большую часть времени он проходит вплоть до определенного драйвера контроллера диска (имя файла → файловая система /VFS → блочное устройство → драйвер устройства), где команда для извлечения блока на диске передается на соответствующее оборудование, которое является очень быстрая работа большую часть времени.
Затем процесс переводится в состояние сна (в пространстве ядра блокировка называется спящей - ничто никогда не "блокируется" с точки зрения ядра). Он будет пробужден после того, как оборудование наконец-то извлечет нужные данные, затем процесс будет помечен как работоспособный и будет запланирован. В конце концов, планировщик запустит процесс.
Наконец, в пользовательском пространстве системный вызов блокировки возвращается с надлежащим состоянием и данными, и поток программы продолжается.
Можно вызвать большинство системных вызовов ввода/вывода в неблокирующем режиме (см. O_NONBLOCK
в open(2)
и fcntl(2)
). В этом случае системные вызовы возвращаются немедленно и сообщают только об отправке операции на диске. Программист должен будет позже в явном виде проверить, успешно ли выполнена операция, успешно или нет, и извлечь ее результат (например, с помощью select(2)
). Это называется асинхронным программированием или программированием на основе событий.
Большинство ответов, в которых упоминается состояние D (которое называется TASK_UNINTERRUPTIBLE
в именах состояний Linux), являются неверными. Состояние D - это особый режим ожидания, который запускается только в пути кода пространства ядра, когда этот путь кода не может быть прерван (поскольку он слишком сложен для программирования), ожидая, что он будет блокироваться только в течение очень длительного времени. короткое время. Я считаю, что большинство "D-состояний" на самом деле невидимы; они очень недолговечны и не могут быть обнаружены такими инструментами, как "top".
Вы можете столкнуться с неубиваемыми процессами в состоянии D в нескольких ситуациях. NFS славится этим, и я сталкивался с этим много раз. Я думаю, что есть некоторое семантическое коллизия между некоторыми путями кода VFS, которые предполагают, что они всегда достигают локальных дисков и быстрого обнаружения ошибок (на SATA время ожидания ошибки составляет около нескольких 100 мс), и NFS, которая фактически выбирает данные из сети, которые является более устойчивым и имеет медленное восстановление (обычное время ожидания TCP составляет 300 секунд). Прочитайте эту статью для TASK_KILLABLE
решения, представленного в Linux 2.6.25 с состоянием TASK_KILLABLE
. До этой эры был хак, когда вы могли отправлять сигналы клиентам процесса NFS, отправляя SIGKILL в поток ядра rpciod
, но забудьте об этом уродливом трюке…
Ответ 3
Процесс, выполняющий ввод/вывод, будет переведен в состояние D (непрерывный сон), который освобождает процессор до тех пор, пока не произойдет аппаратное прерывание, которое сообщает CPU о возврате к выполнению программы. См. man ps
для других состояний процесса.
В зависимости от вашего ядра существует планировщик процессов, который отслеживает запуск готовых процессов. Он, наряду с алгоритмом планирования, сообщает ядру, который обрабатывает, чтобы назначить на какой процессор. Процессы ядра и пользовательские процессы необходимо учитывать. Каждому процессу выделяется срез времени, который является куском времени процессора, которое разрешено использовать. Как только процесс использует весь свой временной срез, он помечается как истек и получает более низкий приоритет в алгоритме планирования.
В ядре 2.6 существует O (1) планировщик сложности времени, поэтому независимо от того, сколько процессов у вас запущено, оно будет назначать процессоры в постоянном режиме время. Однако это сложнее, так как в 2.6 введена предварительная настройка и балансировка загрузки процессора - это не простой алгоритм. В любом случае его эффективные и процессоры не будут оставаться бездействующими, пока вы ждете ввода-вывода.
Ответ 4
Как уже объяснялось другими, процессы в состоянии "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
файловая система не была отключена, поскольку она была занята, но связанный с ней процесс просыпался, и я смог решить проблему без перезагрузки.
Ответ 5
Предполагая, что ваш процесс является единственным потоком, и что вы используете блокирующий ввод-вывод, ваш процесс блокирует ожидание завершения ввода-вывода. Ядро выберет другой процесс, который будет выполняться тем временем, основываясь на хорошем, приоритетном, последнем времени выполнения и т.д. Если нет других запущенных процессов, ядро не будет работать; вместо этого он сообщит аппарату, что машина находится в режиме ожидания (что приведет к снижению энергопотребления).
Процессы, ожидающие завершения ввода-вывода, обычно отображаются в состоянии D, например, ps
и top
.
Ответ 6
Да, задача блокируется в системном вызове read(). Другая задача, которая готова к запуску или если другие задачи не готовы, запускается незанятая задача (для этого ЦП).
Нормальное чтение блокирующего диска заставляет задачу войти в состояние "D" (как отмечали другие). Такие задачи способствуют усреднению нагрузки, даже если они не потребляют процессор.
Некоторые другие типы IO, особенно ttys и network, не ведут себя совершенно одинаково - процесс заканчивается в состоянии "S" и может быть прерван и не учитывается в среднем по загрузке.
Ответ 7
Да, задачи, ожидающие ввода-вывода, блокируются, и выполняются другие задачи. Выбор следующей задачи выполняется планировщик Linux.
Ответ 8
Как правило, процесс блокируется. Если операция чтения находится в файловом дескрипторе, помеченном как неблокирующее, или если процесс использует асинхронный ввод-вывод, он не будет блокироваться. Кроме того, если в процессе есть другие потоки, которые не заблокированы, они могут продолжать работать.
Решение о том, какой процесс запускается дальше, зависит от планировщик в ядре.