Linux进程状态


89

在Linux中,当需要从磁盘读取块时,进程状态会发生什么变化?被封锁了吗?如果是这样,如何选择另一个流程来执行?

Answers:


86

在等待文件描述符返回read()write()从文件描述符返回时,该过程将进入一种特殊的睡眠状态,称为“ D”或“磁盘睡眠”。这很特殊,因为在这种状态下无法终止或中断该进程。等待ioctl()返回的进程也将以这种方式进入睡眠状态。

例外情况是,当文件(例如终端或其他字符设备)以O_NONBLOCK模式打开时,如果假定文件(例如调制解调器)需要时间来初始化,则通过该文件。但是,您在问题中指出了阻止设备。另外,我从未尝试过以ioctl()非阻塞模式打开的fd可能会阻塞的(至少是在不知情的情况下)。

如何选择另一个进程完全取决于您使用的调度程序,以及其他进程可能在该调度程序中修改其权重的方法。

已知某些用户空间程序在某些情况下会一直保持这种状态,直到重新启动为止。这些通常与其他“僵尸”归为一组,但该术语不正确,因为它们在技术上并未失效。


1
“等待ioctl()返回的进程也将以这种方式进入睡眠状态”。我只是杀死了等待阻塞的IOCTL的用户空间进程,所以事实并非如此。除非我missunderstanding
Hamzahfrq

这将是极其困难的时候这样的测试。不间断的进程不能被杀死;如果您能够杀死它,则它只是在阻塞(内核不在ioctl的任何部分的中间,而是将任何相应的响应复制到您通过的位置的用户空间(或者至少不在该位置)。复制中间))。自2009年编写以来,Linux也发生了很大变化。这种现象远没有从前那样可观察到。
蒂姆·波斯特

133

当某个进程需要从磁盘中获取数据时,它实际上会停止在CPU上运行以让其他进程运行,因为该操作可能需要很长时间才能完成-至少需要5ms的磁盘寻道时间,而5ms就是1000万从程序的角度来看,CPU周期是永恒的!

从程序员的角度(也称为“在用户空间中”),这称为阻塞系统调用。如果您进行调用write(2)(这是同名系统调用周围的薄libc包装器),则您的进程不会完全在该边界处停止;它继续在内核中运行系统调用代码。在大多数情况下,它一直一直到特定的磁盘控制器驱动程序(文件名→文件系统/ VFS→块设备→设备驱动程序),在该驱动程序中,将要在磁盘上获取块的命令提交给适当的硬件,这是非常重要的。大多数时候都可以快速操作。

然后,该过程将进入睡眠状态(在内核空间中,阻塞称为睡眠-从内核的角度来看,从来没有“阻塞”任何东西)。一旦硬件最终获取了正确的数据,它将被唤醒,然后该过程将被标记为可运行并进行调度。最终,调度程序将运行该过程。

最后,在用户空间中,阻塞的系统调用将返回正确的状态和数据,并且程序流继续进行。

它可以调用大部分的I / O系统调用非阻塞模式(见O_NONBLOCKopen(2)fcntl(2))。在这种情况下,系统调用立即返回,并且仅报告提交磁盘操作。程序员将不得不在稍后的时间显式检查操作是否成功完成,并获取其结果(例如使用select(2))。这称为异步或基于事件的编程。

这里提到D状态TASK_UNINTERRUPTIBLE在Linux状态名称中称为D状态)的大多数答案都是错误的。在d状态是一种特殊的睡眠模式,这是只有在内核空间的代码路径,当代码路径引发不能被中断(因为这将是太复杂,程序),并期望它只会阻止了很短时间。我相信大多数“ D状态”实际上是不可见的。它们的寿命很短,无法通过“ top”之类的采样工具进行观察。

在某些情况下,您会在D状态下遇到无法杀死的进程。NFS为此而闻名,我已经遇到过很多次了。我认为某些VFS代码路径之间存在语义冲突,它们假定总是到达本地磁盘并进行快速错误检测(在SATA上,错误超时将在几百毫秒左右),而NFS实际上从网络中获取数据,更具弹性,恢复速度较慢(TCP超时通常为300秒)。阅读本文,了解带有TASK_KILLABLE状态的Linux 2.6.25中引入的出色解决方案。在这个时代之前,有一种黑客,您实际上可以通过将SIGKILL发送到内核线程来向NFS进程客户端发送信号rpciod,但是请不要理会这个丑陋的把戏。


2
+1表示详细答复,但请注意,该主题已经接受了近两年的答案。如果您想了解更多新问题,请点击“问题”链接。欢迎使用Stack Overflow,感谢您的贡献!
GargantuChet

20
这个答案是唯一提及NFS的答案,它在某些环境下是D状态下进程的最常见解释。+1。
Pinko

14
很好的答案,谢谢。另请注意,在等待换出的页面时,进程进入D状态,因此,重动进程将长时间处于D状态。
cha0site 2012年

@zerodeux很好的答案,但是我认为您的架构(文件名->文件系统/ VFS->块设备->设备驱动程序)应该是(文件名-> VFS->文件系统(ext3)->块设备->设备驱动程序)
c4f4t0r 2014年

1
是否可以安全地假设内核在等待自旋锁上花费的时间(可能与磁盘I / O相关或无关)全部报告为D状态/proc/stat
威克

8

执行I / O的进程将进入D状态(不间断睡眠),这将释放CPU,直到发生硬件中断,告诉CPU返回执行程序为止。有关man ps其他过程状态,请参见。

根据您的内核,有一个Process Scheduler,它跟踪准备好要执行的进程的运行队列。它与调度算法一起,告诉内核将哪个进程分配给哪个CPU。有内核进程和用户进程要考虑。每个进程都分配了一个时间片,这是允许使用的大量CPU时间。一旦进程使用了​​所有时间片,就将其标记为已过期,并在调度算法中将其赋予较低的优先级。

2.6内核中,有一个O(1)时间复杂度调度程序,因此,无论您正在运行多少个进程,它都会以恒定的时间分配CPU。但是,由于2.6引入了抢占,因此CPU负载平衡并不是一个简单的算法,因此更为复杂。在任何情况下,它都是高效的,并且在您等待I / O时CPU不会保持空闲状态。


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

我发现,将带有-f(force)开关的umount命令提供给相关的已挂载nfs文件系统,可以唤醒睡眠过程:

umount -f /auto/pippo

文件系统没有卸载,因为它很忙,但是相关进程确实唤醒了,我能够解决问题而无需重新启动。


1

假设您的进程是一个单线程,并且您正在使用阻塞I / O,则您的进程将阻塞等待I / O完成。内核将根据优先级,优先级,上次运行时间等选择要同时运行的另一个进程。如果没有其他可运行的进程,则内核将不会运行。相反,它会告诉计算机机器处于空闲状态(这将降低功耗)。

等待I / O完成的进程通常显示在状态D中,例如ps和中top


我使用了大约10%的总内存启动了几个进程。我注意到其中许多处于D状态。这是由于此特定计算机上的IO速度慢吗?假设我有9个进程,它们可能正在争夺IO,其中许多处于D状态。
Kemin Zhou

@KeminZhou与CPU速度相比,I / O非常慢-甚至是快速I / O。单个I / O繁重的过程可以轻松使磁盘甚至SSD繁忙。10个I / O繁重的进程可能会占用很多时间。
derobert

1

是的,该任务在read()系统调用中被阻止。准备运行的另一个任务运行,或者如果没有其他准备就绪的任务,则运行空闲任务(针对该CPU)。

正常的阻止磁盘读取会导致任务进入“ D”状态(如其他人所述)。即使这些任务没有消耗CPU,它们也会有助于平均负载。

某些其他类型的IO(尤其是ttys和network)的行为也不尽相同-该过程最终以“ S”状态结束,并且可以被中断并且不计入平均负载。



0

通常,该过程将阻止。如果读取操作在标记为非阻塞的文件描述符上进行,或者该进程使用异步IO,则不会阻塞。同样,如果该进程具有未被阻塞的其他线程,则它们可以继续运行。

关于下一步运行哪个进程的决定取决于内核中的调度程序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.