Состояния процессов Linux

90

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

Блэр
источник

Ответы:

88

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

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

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

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

Тим Пост
источник
1
«Процесс, ожидающий возврата от ioctl (), также будет усыплен таким образом». Я просто убил свой процесс пользовательского пространства, ожидая блокирующего IOCTL, так что это неправда. Если я не неправильно понял
Hamzahfrq
Было бы чрезвычайно трудно рассчитать время для такого испытания. Непрерывные процессы невозможно убить; если вы смогли убить его, то это была просто блокировка (ядро не было в середине какой-либо части ioctl и скопировало любой соответствующий ответ в пользовательское пространство в том месте, которое вы прошли (или, по крайней мере, не было в середина копирования)). Linux также изменился много с 2009 года , когда это было написано; это явление гораздо менее заметно, чем когда-то.
Тим Пост
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, но забыть об этом уродливом трюке ...

zerodeux
источник
2
+1 за подробный ответ, но обратите внимание, что в этой ветке есть принятый ответ в течение почти двух лет. Нажмите ссылку «Вопросы», если вы хотите помочь с новыми вопросами. Добро пожаловать в Stack Overflow и спасибо за ваш вклад!
GargantuChet
20
Это единственный ответ, в котором упоминается NFS, которая в некоторых средах является наиболее распространенным объяснением процессов в состоянии D. +1.
Pinko
14
Очень хороший ответ, спасибо. Также обратите внимание, что процесс переходит в состояние D во время ожидания страниц, которые были выгружены, поэтому процесс перебивки будет находиться в состоянии D долгое время.
cha0site
@zerodeux хороший ответ, но я думаю, что ваша схема (имя файла -> файловая система / VFS -> блочное устройство -> драйвер устройства) должна быть (имя файла -> VFS -> файловая система (ext3) -> блочное устройство -> драйвер устройства)
c4f4t0r
1
Можно ли предположить, что время, затраченное ядром на ожидание спин-блокировок (которые могут или не могут быть связаны с дисковым вводом-выводом), все сообщается как D-состояние /proc/stat?
wick
8

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

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

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

user224579
источник
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.

Derobert
источник
Я запустил несколько процессов, используя около 10% общей памяти. Я заметил, что многие из них находятся в состоянии D. Это связано с медленным вводом-выводом на этой конкретной машине? Скажем, у меня 9 процессов, они могут конкурировать за ввод-вывод, и многие из них находятся в состоянии D.
Zhou
@KeminZhou По сравнению со скоростью процессора, ввод-вывод довольно медленный - даже быстрый ввод-вывод. Один тяжелый процесс ввода-вывода может легко занять магнитный диск, даже SSD. 10 тяжелых процессов ввода-вывода могут быть заняты довольно многими.
derobert
1

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

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

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

MarkR
источник
0

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

Мартин против Лёвиса
источник
0

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

Решение о том, какой процесс запускается следующим, принимает планировщик в ядре.

Бенно
источник