5

似乎不能将常规文件的写入/读取设为非阻塞。我找到了以下支持参考:

来自 Linux 编程接口:Linux 和 UNIX 系统编程手册:

"--- 非阻塞模式可用于设备(​​例如,终端和伪终端)、管道、FIFO 和套接字。(因为管道和套接字的文件描述符不是使用 open() 获得的,我们必须使用 fcntl 启用此标志() F_SETFL 操作在 5.3 节中描述。​​) O_NONBLOCK 通常对常规文件被忽略,因为内核缓冲区缓存确保常规文件上的 I/O 不会阻塞,如 13.1 节所述。但是,O_NONBLOCK 确实对常规文件有影响使用强制文件锁定时的文件(第 55.4 节)。---"

来自 UNIX 环境中的高级编程第 2 版:

"--- 我们也说过,与磁盘 I/O 相关的系统调用并不被认为是慢的,即使磁盘文件的读取或写入会暂时阻塞调用者。---"

来自http://www.remlab.net/op/nonblock.shtml

“--- 常规文件总是可读的,它们也总是可写的。这在相关的 POSIX 规范中明确说明。我不能强调这一点。将常规文件置于非阻塞状态除了更改一位之外绝对没有任何影响文件标志。从常规文件中读取可能需要很长时间。例如,如果它位于繁忙的磁盘上,I/O 调度程序可能需要很长时间,以至于用户会注意到应用程序被冻结。然而,非-阻塞模式不起作用。它根本不起作用。检查文件的可读性或可写性总是立即成功。如果系统需要时间来执行 I/O 操作,它将使任务进入不可中断的睡眠状态或编写系统调用。---"

当内存足够可用时,通过内核缓冲执行读/写。

我的问题是:是否存在内核内存不足导致缓冲无法立即使用的情况?如果是,内核会做什么?只是返回一个错误或做一些惊人的技巧?

多谢你们!

4

1 回答 1

0

我对 O_NONBLOCK 和引用文本的看法:

  • 如果触发实际磁盘 I/O 的系统调用阻塞或不等待 I/O 完成,则 O_NONBLOCK 绝对没有效果。O_NONBLCOK 仅影响文件系统级别的操作,例如访问伪文件(如第一个引用所述)和锁定文件。O_NONBLOCK 不会影响块设备级别的任何操作。

  • 内存不足与 O_NONBLOCK 无关。

  • O_NONBLOCK 指示对锁定文件的访问是否被阻止。例如,flock() / lockf() 可用于锁定文件。如果使用 O_NONBLOCK,read()/write() 将立即返回 EGAIN,而不是阻塞并等待文件锁被释放。请记住,这种同步差异是在文件系统级别实现的,与 read()/write() 系统调用是否触发真正的磁盘 I/O 无关。

  • 第一个引用的片段because the kernel buffer cache ensures that I/O on regular files does not block具有误导性,我会认为它是错误的。缓冲确实降低了文件读/写系统调用导致磁盘 I/O 并因此阻塞的机会,但是,单独缓冲永远不能完全避免 I/O。如果一个文件没有被缓存,当你从文件中读取()时内核需要执行一个实际的 IO。如果你 write() 到文件并且页面缓存充满了脏页,内核必须通过首先将一些数据刷新到存储设备来腾出空间。我觉得如果你在精神上跳过这个片段,文本会变得更加清晰。

  • 第二个引用似乎很笼统(慢是什么意思?)并且没有解释为什么与 I/O 相关的调用不被认为是慢的。我怀疑它周围的文本中有更多的背景信息,这更符合作者的意图。

  • 内核中的内存不足有两种形式:(a) 缓冲区高速缓存中缺少空闲页面和 (b) 没有足够的内存来分配新的数据结构来服务新的系统调用。对于 (a) 内核简单地回收缓冲区高速缓存中的页面,可能通过首先将脏页面写入磁盘。这是一个非常常见的场景。对于(b)内核需要通过将程序数据分页到交换分区来释放内存,或者(如果失败)甚至通过杀死现有进程(调用 OOM 函数,这几乎会杀死内存消耗最大的进程) . 这是一种不常见的操作模式,但在用户进程被杀死后系统将继续运行。

于 2015-08-04T11:54:41.817 回答