Linux进程状态

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

Solutions Collecting From Web of "Linux进程状态"

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

这是一个例外情况,当文件(如终端或其他字符设备)以O_NONBLOCK模式打开时,假设设备(如调制解调器)需要时间进行初始化时通过。 但是,您在问题中指出了块设备。 此外,我从来没有尝试过一个ioctl() ,它可能阻止在非阻塞模式下打开的fd(至少不知道)。

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

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

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

从程序员的角度(也称为“在用户空间”),这被称为阻塞系统调用 。 如果您调用write(2) (这是一个名称相同的系统调用的精简libc包装器),那么您的进程并不会完全停留在该边界上:它在内核侧继续运行系统调用代码。 大多数情况下,它一直到特定的磁盘控制器驱动程序(文件名→文件系统/ VFS→块设备→设备驱动程序),其中一个命令获取磁盘上的块提交给适当的硬件:这是一个非常快速操作大部分时间。

那么进程处于睡眠状态 (在内核空间中,阻塞被称为睡眠 – 从内核的角度来看,任何事情都不会被阻塞)。 一旦硬件最终获取了正确的数据,它将会再次唤醒,然后一旦调度程序允许,该进程将被标记为可运行 ,预定并运行。

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

可以在非阻塞模式下调用大多数I / O系统调用(请参见open(2)fcntl(2) O_NONBLOCK )。 在这种情况下,系统会立即调用返回值,只会说明磁盘操作的正确提交。 程序员将不得不在晚些时候明确地检查操作是否完成,是否成功,并获取结果(例如select(2) )。 这被称为异步或基于事件的编程。

这里大多数的答案都提到了D状态 (从Linux状态名称确切的名字是TASK_UNINTERRUPTIBLE )是不正确的。 D状态是一种特殊的睡眠模式,它只在内核空间代码路径中触发,当代码路径不能被中断 (因为编程复杂),大部分时间希望阻塞很快。 我相信大多数“D国”实际上是看不见的,它们是非常短暂的,不能通过诸如“顶”之类的抽样工具来观察。

但在某些情况下,你有时会遇到D状态下那些不可驱动的进程。 NFS很有名,我遇到过很多次。 我认为在一些VFS代码路径之间存在语义上的冲突,这些代码路径总是到达本地磁盘和快速错误检测(在SATA上,错误超时大概在100毫秒左右),实际上从网络获取数据的NFS更多恢复速度慢(300秒的TCP超时是常见的)。 请阅读本文 ,了解Linux 2.6.25中引入的TASK_KILLABLE状态的解决方案。 在这个时代之前,你可以通过向内核线程rpciod发送一个SIGKILL来实际发送信号给NFS进程客户端,但忘记了这个丑陋的技巧。

执行I / O的进程将被置于D状态(不间断休眠) ,释放CPU,直到有硬件中断告诉CPU返回执行程序。 请参阅man ps了解其他进程状态。

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

2.6内核中 ,有一个O(1)时间复杂度的调度器 ,所以无论你运行多少个进程,它都会定时分配CPU。 但是更复杂的是,由于2.6引入抢占和CPU负载均衡不是一个简单的算法。 无论如何,这是有效的,CPU等待I / O时不会闲置。

正如其他人已经解释过的,处于“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(强制)开关,挂载到相关的nfs文件系统,能够唤醒睡眠进程:

 umount -f /auto/pippo 

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

假设你的进程是一个单线程,并且你正在使用阻塞I / O,你的进程将阻塞等待I / O完成。 如果没有其他可运行的进程,内核将不会运行任何内核,而内核会根据优先级,优先级,最后运行时间等选择另一个进程运行。 相反,它会告诉硬件机器空闲(这将导致更低的功耗)。

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

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

正常的阻塞光盘读取会导致任务进入“D”状态(正如其他人已经注意到的那样)。 这些任务有助于平均负载,即使它们不占用CPU。

一些其他类型的IO,特别是ttys和网络,并不完全相同 – 过程最终处于“S”状态,可以被中断,并且不计算负载平均值。

是的,等待IO的任务被阻塞,其他任务被执行。 选择下一个任务是由Linux调度程序完成的。

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

关于接下来运行哪个进程的决定取决于内核中的调度器 。