【问题标题】:Can `read()` be directly followed by `write()` and `write()` by `read()`?`read()` 可以直接跟在`write()` 后面,`write()` 跟在`read()` 后面吗?
【发布时间】:2018-08-30 18:47:50
【问题描述】:

In the C standard library, an output can't be followed by an input and vice versa.

对于Linux API,read()可以直接跟write()write()read()吗?如果是,为什么 Linux API 和 C 库 IO API 有这么大的区别?

谢谢。

【问题讨论】:

  • 我很想将其作为另一个问题的副本关闭。 FILE 限制的原因是必须正确管理的内部缓冲区。文件描述符只是整数;他们没有附加缓冲区。

标签: c linux io


【解决方案1】:

您的其他问题(已链接)缺少一些上下文。当它说“当打开文件进行读写时(类型中的加号),有两个限制。”,它指的是使用FILE *流打开和操作的文件(例如,fopen,@ 987654323@、fprintf 等)- 不是对文件描述符进行操作的那些(例如,openreadwrite 等)。

只有FILE * 流通常具有关联的 stdio 缓冲区;文件描述符没有任何关联的缓冲区(可能还有其他较低级别的缓冲区,例如内核、磁盘控制器等 - 但这是您通常不必担心的事情)。所以read(2)write(2) 不缓冲任何东西(没有stdio 缓冲区)。所以他们没有这样的 I/O 顺序限制。

【讨论】:

    【解决方案2】:

    回顾另一个答案,当使用 stdio 时,您正在使用一个不是实际文件的缓冲区。如果您正在阅读,则必须从实际文件中复制该缓冲区(通过 OS read 调用),如果您正在写入,则必须将其复制到实际文件(通过 OS write 调用)。如果你过于仓促地从写入切换到读取,stdio 代码不会意识到它必须刷新写入的缓冲区并重新加载缓冲区以进行读取。

    另一方面,当使用readwrite 系统调用时,情况有所不同。一方面,您可能正在读取和写入设备(如串行端口或 TCP 网络流),在这种情况下,在读取和写入之间跳转显然没有问题。

    但是,即使您使用readwrite 系统调用来读取和写入文件,您也是在直接访问该文件——或者至少是操作系统的文件概念。提到的 stdio 缓冲区问题均不适用。

    (具有讽刺意味的是,操作系统通常也使用一个或多个文件块的缓冲副本。但实现完全不同,如果您在读取之间来回切换,最终不会有任何问题和写作。)

    正如另一个答案中所解释的,stdio 例程可以被编写来支持交错 i/o,但为了简单和高效,它们不是。

    为什么会这样?另一个难题是,在 C 和 Unix 的早期,系统调用非常昂贵。系统调用可能比普通函数调用花费 10 或 100 倍的时间。因此,避免不必要的系统调用非常重要,stdio 库是其中的重要组成部分。它需要一个read 调用来填充缓冲区,然后您可以进行大量小调用以从缓冲区中获取单个(或少量)字符,而不会产生更多开销。同样,在写入时,您可以进行大量小调用来写入少量字符,然后只需一个昂贵的 write 调用来刷新缓冲区。让 stdio 支持交错读取和写入——这不被视为一个重要的用例——将需要更多的系统调用、更多的测试或更多的代码(或全部三个),而且通常会比它更昂贵值得。

    (今天,系统调用的效率要低得多,所以如果今天从头开始设计 C 和 Unix,那么 readwrite 系统调用与 stdio 输入和输出调用之间的区别可能已经解决了不同。)

    【讨论】:

      猜你喜欢
      • 2021-01-13
      • 1970-01-01
      • 1970-01-01
      • 2015-01-10
      • 1970-01-01
      • 2019-04-03
      • 1970-01-01
      • 2012-12-03
      相关资源
      最近更新 更多