可以在read()之后直接跟着write()和在write()之后跟着read()吗?

时间:2018-08-30 18:47:51

标签: c linux io

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有如此大的区别?

谢谢。

2 个答案:

答案 0 :(得分:2)

您的其他问题(链接的)缺少上下文。当它说“打开文件进行读写(类型中的加号)时,有两个限制。”,它表示使用FILE *流(例如{{1 }},fopenfscanf等),而不是对文件描述符(例如,fprintfopenread等)进行操作的对象。 / p>

通常只有write个流具有关联的stdio缓冲区;文件描述符没有任何关联的缓冲区(可能还有其他较低级别的缓冲区,例如内核,磁盘控制器等,但这通常不必担心)。因此FILE *read(2)不缓冲任何内容(没有stdio缓冲区)。因此,它们没有这样的I / O订单限制。

答案 1 :(得分: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输入和输出调用之间的区别可能会有所不同。产生了很大的不同。)