Hat*_*ick 5 linux filesystems io kernel
看来对常规文件的写入/读取不能成为非阻塞的。我找到了以下支持参考:
摘自《Linux 编程接口:Linux 和 UNIX 系统编程手册》:
"--- 非阻塞模式可以与设备(例如,终端和伪终端)、管道、FIFO 和套接字一起使用。(因为管道和套接字的文件描述符不是使用 open() 获得的,所以我们必须使用 fcntl 启用此标志() F_SETFL 操作在第 5.3 节中描述。) O_NONBLOCK 对于常规文件通常被忽略,因为内核缓冲区高速缓存确保常规文件上的 I/O 不会阻塞,如第 13.1 节中所述。但是,O_NONBLOCK 对常规文件确实有影响使用强制文件锁定时的文件(第 55.4 节)。 ---”
来自 UNIX 环境中的高级编程第二版:
“--- 我们还说过,与磁盘 I/O 相关的系统调用并不被认为是慢的,即使磁盘文件的读取或写入可能会暂时阻塞调用者。---”
来自http://www.remlab.net/op/nonblock.shtml:
“--- 常规文件总是可读的,也总是可写的。这一点在相关的 POSIX 规范中有明确规定。这一点我怎么强调都不为过。将常规文件置于非阻塞状态除了改变其中的一位之外绝对没有任何影响。文件标志。从常规文件读取可能需要很长时间。例如,如果它位于繁忙的磁盘上,I/O 调度程序可能会花费太多时间,以至于用户会注意到应用程序被冻结。尽管如此,非-阻塞模式不起作用。它根本不起作用。检查文件的可读性或可写性总是立即成功。如果系统需要时间来执行 I/O 操作,它会将任务从读取状态置于不可中断睡眠状态或者编写系统调用。---”
当内存足够可用时,通过内核缓冲执行读/写。
我的问题是:是否存在内核内存不足导致缓冲无法立即使用的情况?如果是,内核会做什么?简单地返回一个错误或执行一些惊人的技巧?
多谢你们!
我对 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。如果文件未缓存,则当您从文件中 read() 时,内核需要执行实际的 IO。如果您 write() 到文件并且页面缓存已满了脏页面,则内核必须首先将一些数据刷新到存储设备来腾出空间。我觉得如果你在心里跳过这个片段,文字就会变得更加清晰。
第二个引用看起来很通用(慢是什么意思?)并且没有解释为什么与 I/O 相关的调用不被认为是慢的。我怀疑文本中包含更多背景信息,更符合作者的意图。
内核内存不足可能有两种形式:(a) 缓冲区高速缓存中缺少空闲页;(b) 没有足够的内存来分配新的数据结构来服务新的系统调用。对于(a),内核简单地回收缓冲区高速缓存中的页面,可能通过首先将脏页面写入磁盘来实现。这是一个非常常见的场景。对于(b),内核需要通过将程序数据分页到交换分区或者(如果失败)甚至通过杀死现有进程(调用 OOM 函数,这几乎杀死了内存消耗最大的进程)来释放内存。 。这是一种不常见的操作模式,但在用户进程被杀死后系统将继续运行。