慢速系统调用和快速系统调用有什么区别?我了解到,如果进程捕获一些信号,慢速系统调用可能会阻塞,因为捕获的信号可能会唤醒被阻塞的系统调用,但我无法完全理解这种机制。任何例子将不胜感激。
答案1
事实上,系统调用分为三个层次。
- 有些系统调用会立即返回。 “立即”意味着他们唯一需要的就是一点处理器时间。他们可以花多长时间没有硬性限制(除了实时系统),但这些呼叫一旦被安排足够长的时间就会返回。
这些调用通常称为非阻塞。非阻塞调用的示例是仅读取一点系统状态的调用,或对系统状态进行简单更改的调用,例如getpid
,gettimeofday
,getuid
或者setuid
。有些系统调用可以是阻塞的,也可以是非阻塞的,具体取决于具体情况;例如read
如果文件是管道或其他支持非阻塞读取的类型,则永远不会阻塞O_NONBLOCK
旗帜已设置。 - 一些系统调用可能需要一段时间才能完成,但不会永远完成。一个典型的例子是
sleep
。 - 有些系统调用只有在某些外部事件发生后才会返回。据说这些电话是阻塞。例如,
read
对阻塞文件描述符的调用是阻塞的,所以也是wait
。
“快”和“慢”系统调用之间的区别接近于非阻塞与阻塞,但这次是从内核实现者的角度来看的。快速系统调用是已知能够在不阻塞或等待的情况下完成的系统调用。当内核遇到快速系统调用时,它知道它可以立即执行系统调用并保持同一进程的调度。 (在某些操作系统中非抢占式多任务、快速系统调用可能是非抢占式的;正常的 UNIX 系统中并非如此。)另一方面,缓慢的系统调用可能需要等待另一个任务完成,因此内核必须准备暂停调用进程并运行另一个任务。
有些案例有点灰色地带。例如,磁盘读取(read
从常规文件)通常被认为是非阻塞的,因为它不等待另一个进程;它只是等待磁盘,通常只需要一点时间来应答,但不会永远等待(所以这是上面的情况 2)。但从内核的角度来看,该过程必须等待磁盘驱动程序完成,因此这绝对是一个缓慢的系统调用。
答案2
缓慢的系统调用类似于 TCP 套接字 read() - 如果您没有设置 O_ASYNC (或其他),它可能会永远等待。
快速系统调用类似于 gettimeofday() 或 getpid(),它们都将内核立即可用的信息返回给进程。
磁盘读取属于缓慢系统调用的范畴。如果进程对一个真正的磁盘文件、文件描述符执行 read(),则内核可能必须读取一个或多个磁盘块才能满足读取要求。根据底层文件系统的磁盘结构,这可能意味着读取磁盘索引节点以获取“间接块”的磁盘块号,读取间接块以获取数据块,然后读取数据块本身。相当耗时,至少就每次磁盘访问的 CPU 周期而言,现在可能比过去的美好时光还要糟糕。
我已经很久没有见过这种情况了,但是旧 Unix 磁盘驱动器设备驱动程序代码的“下半部分”会阻止信号/中断,以便更容易维护磁盘文件系统的完整性。有时,有问题的驱动程序或发生故障的磁盘永远不会提供进程请求的磁盘块,并且进程会永远休眠。即使是kill-9也无济于事。