Что происходит в Linux с состоянием процесса, когда ему нужно прочитать блоки с диска? Это заблокировано? Если да, то как выбрать для выполнения другой процесс?
Ответы:
Во время ожидания read()
или write()
в / от возвращения дескриптора файла, то процесс будет помещен в особом виде сна, известный как «D» или «Disk Sleep». Это особенное, потому что процесс не может быть остановлен или прерван в таком состоянии. Процесс, ожидающий возврата от ioctl (), также будет переведен в спящий режим.
Исключением является ситуация, когда файл (например, терминал или другое символьное устройство) открывается в O_NONBLOCK
режиме, передаваемом, когда предполагается, что устройству (например, модему) потребуется время для инициализации. Однако в своем вопросе вы указали блочные устройства. Кроме того, я никогда не пробовал такой, ioctl()
который может блокировать fd, открытый в неблокирующем режиме (по крайней мере, сознательно).
Выбор другого процесса полностью зависит от используемого вами планировщика, а также от того, что другие процессы могли сделать для изменения своего веса в этом планировщике.
Известно, что некоторые программы пользовательского пространства при определенных обстоятельствах остаются в этом состоянии навсегда, до перезагрузки. Обычно они сгруппированы вместе с другими «зомби», но этот термин будет неправильным, поскольку технически они не прекратили свое существование.
Когда процессу необходимо получить данные с диска, он фактически перестает работать на ЦП, чтобы позволить другим процессам работать, потому что операция может занять много времени - обычно время поиска для диска составляет не менее 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
, но забыть об этом уродливом трюке ...
/proc/stat
?
Процесс, выполняющий ввод-вывод, будет переведен в состояние D (непрерывный сон) , которое освобождает ЦП до тех пор, пока не произойдет аппаратное прерывание, которое сообщает ЦП вернуться к выполнению программы. См. man ps
Другие состояния процесса.
В зависимости от вашего ядра существует планировщик процессов , который отслеживает очередь выполнения процессов, готовых к выполнению. Вместе с алгоритмом планирования он сообщает ядру, какой процесс назначить какому процессору. Следует учитывать процессы ядра и пользовательские процессы. Каждому процессу выделяется временной интервал, который представляет собой кусок процессорного времени, который ему разрешено использовать. Как только процесс использует весь свой временной интервал, он помечается как просроченный и получает более низкий приоритет в алгоритме планирования.
В ядре 2.6 есть планировщик временной сложности O (1) , поэтому независимо от того, сколько процессов у вас запущено, он будет назначать процессоры в постоянное время. Однако это более сложно, поскольку 2.6 представила приоритетное прерывание и балансировка нагрузки ЦП - непростой алгоритм. В любом случае это эффективно, и процессоры не будут простаивать, пока вы ждете ввода-вывода.
Как уже объяснялось другими, процессы в состоянии «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
файловая система не была размонтирована, потому что была занята, но связанный с этим процесс проснулся, и я смог решить проблему без перезагрузки.
Предполагая, что ваш процесс является одним потоком и вы используете блокировку ввода-вывода, ваш процесс будет блокироваться, ожидая завершения ввода-вывода. Ядро тем временем выберет другой процесс для запуска на основе удобства, приоритета, времени последнего выполнения и т. Д. Если нет других запускаемых процессов, ядро не будет запускать их; вместо этого он сообщит оборудованию, что машина простаивает (что приведет к снижению энергопотребления).
Процессы, ожидающие завершения ввода-вывода, обычно появляются в состоянии D, например, ps
и top
.
Да, задача блокируется системным вызовом read (). Выполняется другая готовая задача, или, если другие задачи не готовы, запускается неактивная задача (для этого ЦП).
Нормальное, блокирующее чтение с диска приводит к тому, что задача переходит в состояние «D» (как отмечали другие). Такие задачи увеличивают среднюю нагрузку, даже если они не используют процессор.
Некоторые другие типы ввода-вывода, особенно ttys и сеть, ведут себя иначе - процесс заканчивается в состоянии «S», может быть прерван и не учитывается при средней загрузке.
Да, задачи, ожидающие ввода-вывода, блокируются, а другие задачи выполняются. Выбор следующей задачи выполняется планировщиком Linux .
Обычно процесс блокируется. Если операция чтения выполняется для файлового дескриптора, помеченного как неблокирующий, или если процесс использует асинхронный ввод-вывод, он не будет блокироваться. Также, если у процесса есть другие потоки, которые не заблокированы, они могут продолжить работу.
Решение о том, какой процесс запускается следующим, принимает планировщик в ядре.