Linux进程状态

时间:2009-09-25 06:12:55

标签: linux process kernel cpu states

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

8 个答案:

答案 0 :(得分:123)

当进程需要从磁盘获取数据时,它会有效地停止在CPU上运行以让其他进程运行,因为操作可能需要很长时间才能完成 - 至少5ms寻找磁盘的时间是常见的,并且5ms是1000万CPU周期,从程序的角度来看是永恒的!

从程序员的角度来看(也称“在用户空间”),这称为阻止系统调用。如果你调用write(2)(这是一个围绕同名系统调用的瘦libc包装器),你的进程并不完全停在该边界;它继续在内核中运行系统调用代码。大部分时间它一直到特定的磁盘控制器驱动程序(文件名→文件系统/ VFS→块设备→设备驱动程序),其中获取磁盘上的块的命令被提交到适当的硬件,这是一个非常大部分时间快速操作。

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

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

可以在非阻止模式中调用大多数I / O系统调用(请参阅O_NONBLOCKopen(2)中的fcntl(2))。在这种情况下,系统立即调用return,仅报告提交磁盘操作。程序员必须在以后明确检查操作是否成功完成,并获取其结果(例如,使用select(2))。这称为异步或基于事件的编程。

这里提到 D状态(在Linux状态名称中称为TASK_UNINTERRUPTIBLE)的大多数答案都是错误的。 D 状态是一种特殊的睡眠模式,仅在内核空间代码路径中触发,此代码路径无法中断(因为它太复杂了程序),期望它只能在很短的时间内阻止。我相信大多数“D州”实际上是看不见的;它们非常短暂,无法通过“顶部”等采样工具观察到。

在某些情况下,您可以在D状态下遇到无法杀死的进程。 NFS因此而闻名,我已经多次遇到过它。我认为一些VFS代码路径之间存在语义冲突,它们假设总是到达本地磁盘并且快速检测错误(在SATA上,错误超时将在几百毫秒左右),而NFS实际上从网络中获取数据更具弹性并且恢复缓慢(TCP超时为300秒是常见的)。阅读this article,了解Linux 2.6.25中引入的TASK_KILLABLE状态的酷解决方案。在这个时代之前,有一个hack,你可以通过向内核线程rpciod发送一个SIGKILL来实际向NFS进程客户端发送信号,但是忘掉那个丑陋的技巧。...

答案 1 :(得分:80)

在等待文件描述符返回的read()write()时,该进程将被置于一种特殊的睡眠状态,称为“D”或“磁盘睡眠”。这是特殊的,因为在这种状态下不能杀死或中断该过程。等待从ioctl()返回的进程也将以这种方式进入休眠状态。

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

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

在某些情况下,某些用户空间程序已知永远处于此状态,直到重新启动。这些通常与其他“僵尸”分组,但这个术语不正确,因为它们在技术上并不是已经不存在。

答案 2 :(得分:7)

执行I / O的进程将进入 D状态(不间断睡眠),从而释放CPU,直到有硬件中断告诉CPU返回执行程序。有关其他流程状态,请参阅man ps

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

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

答案 3 :(得分: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(强制)开关的umount命令提供给相关的已安装的nfs文件系统,可以唤醒睡眠过程:

umount -f /auto/pippo

文件系统没有卸载,因为它很忙,但相关进程确实已经唤醒,我能够在不重新启动的情况下解决问题。

答案 4 :(得分:1)

假设您的进程是单个线程,并且您正在使用阻塞I / O,那么您的进程将阻止等待I / O完成。内核将根据niceness,priority,last run time等选择另一个进程同时运行。如果没有其他可运行的进程,内核将不会运行任何进程;相反,它会告诉硬件机器处于空闲状态(这将导致更低的功耗)。

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

答案 5 :(得分:1)

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

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

其他一些类型的IO,尤其是ttys和网络,其行为并不完全相同 - 该过程最终处于“S”状态,可能会被中断,并且不会计入负载平均值。

答案 6 :(得分:0)

是,等待IO的任务被阻止,其他任务被执行。选择下一个任务由Linux scheduler完成。

答案 7 :(得分:0)

一般来说,这个过程会阻止。如果读操作是在标记为非阻塞的文件描述符上,或者如果进程使用异步IO,则它不会阻塞。此外,如果进程有其他线程未被阻止,则可以继续运行。

关于下一个进程运行的决定取决于内核中的scheduler