2

write()执行系统调用时到底发生了什么?

假设我有一个程序,它使用write()函数调用将某些数据写入文件。现在 C 库有自己的内部缓冲区,操作系统也有自己的缓冲区。

这些缓冲区之间发生了什么交互?

就像当 C 库缓冲区被完全填满时,它会写入操作系统缓冲区,当操作系统缓冲区被完全填满时,实际的写入是在文件上完成的?

我正在寻找一些详细的答案,有用的链接也会有所帮助。考虑 UNIX 系统的这个问题。

4

6 回答 6

3

write() 系统调用(实际上是所有系统调用)只不过是应用程序和操作系统之间的契约。

  • 对于“普通”文件,write() 仅将数据放在缓冲区上,并将该缓冲区标记为“脏”
  • 在未来的某个时间,这些脏缓冲区将被收集并实际写入磁盘。这可以通过 fsync() 强制执行
  • 这是由挂载文件系统表中的 .write() “方法”完成的
  • 这将调用硬件的 .write() 方法。(这可能涉及另一层缓冲,例如 DMA)
  • 现代硬盘有自己的缓冲区,即使 OS-> 控制器告诉它们,这些缓冲区可能实际上已写入物理磁盘,也可能未写入物理磁盘。

现在,一些(异常文件没有write() 方法来支持它们。想象一下 open()ing "/dev/null",然后 write()ing 一个缓冲区给它。系统可以选择不缓冲它,因为它永远不会被写入。

另请注意, write() 的行为确实取决于文件的性质;对于网络套接字, write(fd,buff,size) 可以在发送 size 个字节之前返回(write 将返回发送的字符数)。但是一旦他们被发送,就不可能知道他们在哪里。它们可能仍然在网络缓冲区中(例如等待 Nagle ...),或网络接口内的缓冲区,或路由器中的缓冲区或线路上某处的交换机。

于 2012-10-24T12:32:06.780 回答
3

我所知道的...

write()函数是一个较低级别的东西,其中库不缓冲数据(与fwrite()库做/可能缓冲数据的地方不同)。

尽管如此,唯一的保证是操作系统在下一次fsync()完成之前将数据传输到磁盘驱动器。但是,硬盘驱动器通常有自己的内部缓冲区,这些缓冲区(有时)超出了操作系统的控制范围,因此即使后续操作fsync()已经完成,也可能在数据从磁盘驱动器的内部缓冲区实际写入之前发生电源故障或其他事情到磁盘的物理介质。

本质上,如果您真的必须确保您的数据实际写入磁盘的物理介质;那么您需要重新设计您的代码以避免此要求,或接受(小)故障风险,或确保硬件能够胜任(例如,获得 UPS)。

于 2012-10-24T12:07:54.837 回答
2

write()将数据写入操作系统,使其对所有进程可见(如果它可以被其他进程读取)。操作系统如何缓冲它,或者它何时被永久写入磁盘,这取决于库、操作系统、系统配置和文件系统。但是,sync()可用于强制刷新缓冲区。

可以保证的是,POSIX 要求,在符合 POSIX 的文件系统上,read()可以证明在 a 返回后发生的 awrite()必须返回写入的数据。

于 2012-10-24T12:03:25.487 回答
0

由于您要求使用 UNIX,因此您必须记住,文件实际上可能位于您已挂载的 FTP 服务器上,例如。例如文件/dev/proc也不是 HDD 上的文件。

此外,在 Linux 上,数据不会直接写入硬盘驱动器,而是有一个轮询过程,它会每隔一段时间刷新所有挂起的写入。

但同样,这些是实现细节,从您的程序的角度来看,它们真的不会影响任何事情。

于 2012-10-24T12:01:51.623 回答
0

取决于操作系统,请参阅man 2 sync和(在 Linux 上)man 8 sync.

于 2012-10-24T12:03:52.260 回答
0

几年前,操作系统应该实现一种“电梯算法”来安排写入磁盘的时间。这个想法是最小化磁盘写入头的移动,这将为同时访问磁盘的多个进程提供良好的吞吐量。

于 2012-10-24T12:06:07.983 回答