write()
执行系统调用时到底发生了什么?
假设我有一个程序,它使用write()
函数调用将某些数据写入文件。现在 C 库有自己的内部缓冲区,操作系统也有自己的缓冲区。
这些缓冲区之间发生了什么交互?
就像当 C 库缓冲区被完全填满时,它会写入操作系统缓冲区,当操作系统缓冲区被完全填满时,实际的写入是在文件上完成的?
我正在寻找一些详细的答案,有用的链接也会有所帮助。考虑 UNIX 系统的这个问题。
write() 系统调用(实际上是所有系统调用)只不过是应用程序和操作系统之间的契约。
现在,一些(异常)文件没有write() 方法来支持它们。想象一下 open()ing "/dev/null",然后 write()ing 一个缓冲区给它。系统可以选择不缓冲它,因为它永远不会被写入。
另请注意, write() 的行为确实取决于文件的性质;对于网络套接字, write(fd,buff,size) 可以在发送 size 个字节之前返回(write 将返回发送的字符数)。但是一旦他们被发送,就不可能知道他们在哪里。它们可能仍然在网络缓冲区中(例如等待 Nagle ...),或网络接口内的缓冲区,或路由器中的缓冲区或线路上某处的交换机。
我所知道的...
该write()
函数是一个较低级别的东西,其中库不缓冲数据(与fwrite()
库做/可能缓冲数据的地方不同)。
尽管如此,唯一的保证是操作系统在下一次fsync()
完成之前将数据传输到磁盘驱动器。但是,硬盘驱动器通常有自己的内部缓冲区,这些缓冲区(有时)超出了操作系统的控制范围,因此即使后续操作fsync()
已经完成,也可能在数据从磁盘驱动器的内部缓冲区实际写入之前发生电源故障或其他事情到磁盘的物理介质。
本质上,如果您真的必须确保您的数据实际写入磁盘的物理介质;那么您需要重新设计您的代码以避免此要求,或接受(小)故障风险,或确保硬件能够胜任(例如,获得 UPS)。
由于您要求使用 UNIX,因此您必须记住,文件实际上可能位于您已挂载的 FTP 服务器上,例如。例如文件/dev
,/proc
也不是 HDD 上的文件。
此外,在 Linux 上,数据不会直接写入硬盘驱动器,而是有一个轮询过程,它会每隔一段时间刷新所有挂起的写入。
但同样,这些是实现细节,从您的程序的角度来看,它们真的不会影响任何事情。
取决于操作系统,请参阅man 2 sync
和(在 Linux 上)man 8 sync
.
几年前,操作系统应该实现一种“电梯算法”来安排写入磁盘的时间。这个想法是最小化磁盘写入头的移动,这将为同时访问磁盘的多个进程提供良好的吞吐量。