当一个进程需要从磁盘中获取数据时,它会有效地停止在CPU上运行,以便让其他进程运行,因为这个操作可能需要很长时间才能完成 - 至少5毫秒的寻道时间对于磁盘来说是常见的,而5毫秒相当于1000万个CPU周期,从程序的角度看,这是永恒的!
从程序员的角度来看(也称为“用户空间”),这称为阻塞系统调用。 如果您调用write(2)
(它是系统调用名称的薄libc封装程序),则您的进程不会在该边界处完全停止; 它将继续在内核中运行系统调用代码。 大多数情况下,它一直走到特定的磁盘控制器驱动程序(文件名→文件系统/VFS→块设备→设备驱动程序),在那里会向适当的硬件提交获取磁盘块的命令,这通常是非常快的操作。
然后,进程被置于睡眠状态(在内核空间中,阻塞被称为睡眠-从内核的角度来看,没有任何东西是“被阻塞”的)。 一旦硬件最终获取了正确的数据,进程将被唤醒,然后进程将被标记为可运行状态并且将被调度。 最终,调度程序将运行该进程。
最后,在用户空间,阻塞系统调用会以适当的状态和数据返回,并且程序流程会继续进行。
大多数I/O系统调用可以在非阻塞模式下调用(请参见open(2)
中的O_NONBLOCK
和fcntl(2)
)。 在这种情况下,系统调用会立即返回,并仅报告提交磁盘操作。 程序员必须在稍后的时间内显式检查操作是否已成功完成,并获取其结果(例如,使用select(2)
)。 这称为异步或基于事件的编程。
大部分提到D状态的回答(在Linux状态名称中被称为TASK_UNINTERRUPTIBLE
)都是错误的。 D 状态是一种特殊的休眠模式,只有在内核空间代码路径中触发时才会出现,当该代码路径无法中断(因为编程过于复杂)时,并期望它只会阻塞很短的时间。我相信大多数“D状态”实际上是看不见的,它们存在时间非常短暂,不能被像“top”这样的采样工具观察到。
你可能会在一些情况下遇到无法被终止的处于D状态的进程。NFS以这种方式闻名,我遇到过许多次。我认为在一些VFS代码路径之间存在语义冲突,它们假设总是能够访问本地磁盘并快速检测错误(在SATA上,错误超时大约是几百毫秒),而NFS实际上从网络获取数据,网络更具有弹性并具有较慢的恢复速度(300秒的TCP超时是常见的)。请参阅此文章,了解在Linux 2.6.25中引入的TASK_KILLABLE
状态的解决方案。在此之前,有一个技巧,可以通过向内核线程rpciod
发送SIGKILL信号来实际发送信号给NFS进程客户端,但请忘记那个丑陋的技巧……
在等待从文件描述符读取(read()
)或向其写入(write()
)时,该进程将处于一种特殊的休眠状态,称为“D”或“磁盘休眠”。这是特殊的,因为在此状态下无法杀死或中断该进程。等待ioctl()
返回的进程也将以这种方式被置于休眠状态。
唯一的例外是当以O_NONBLOCK
模式打开文件(例如终端或其他字符设备),假定设备(如调制解调器)需要时间来初始化时。但是,您在问题中提到的是块设备。此外,我从未尝试过在非阻塞模式下打开的fd上可能会阻塞的ioctl()
(至少不是有意识的)。
另一个进程如何选择完全取决于您使用的调度程序,以及其他进程可能已经执行的操作以修改其在该调度程序中的权重。
某些用户空间程序在某些情况下已知会永远处于此状态,直到重新启动。这些通常与其他“僵尸”一起分组,但该术语并不正确,因为它们在技术上并不失效。
man ps
了解其他进程状态。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 /auto/pippo
是的,在read()系统调用中,任务会被阻塞。另一个准备好的任务会运行,或者如果没有其他准备好的任务,则会运行空闲任务(对于该CPU)。
正常的阻塞磁盘读取会导致任务进入“D”状态(如其他人所述)。即使它们不消耗CPU,这些任务也会对负载平均值产生影响。
一些其他类型的IO,特别是tty和网络,不会完全相同 - 进程最终进入“S”状态,可以被中断,并且不计入负载平均值。
假设您的进程是单线程的,并且您正在使用阻塞式 I/O,则您的进程将会被阻塞等待 I/O 完成。内核将根据 niceness、优先级、上次运行时间等在此期间选择另一个进程来运行。如果没有其他可运行的进程,内核将不会运行任何进程;相反,它将告诉硬件机器处于闲置状态(这将导致功耗降低)。
等待 I/O 完成的进程通常会显示为状态 D,例如 ps
和 top
。
/proc/stat
中报告为D状态吗? - wickD
状态的案例:慢的FUSE文件系统。 - Jonathon Reinhart