writev
函数将struct iovec数组作为输入参数writev(int fd, const struct iovec *iov, int iovcnt);
输入是需要写入文件(例如)的内存缓冲区列表。我想知道的是:
writev是否在内部执行此操作:for (each element in iov) write(element)
这样iov
的每个元素都会在单独的I/O调用中写入文件?还是writev
在单个I/O调用中将所有内容写入文件?
最佳答案
根据标准,由于以下几个原因,您提到的for循环不是writev
的有效实现:
PIPE_BUF
,则管道写必须是原子的,但是该循环会破坏原子性要求。此问题无法解决,除非在总长度最大为PIPE_BUF
的情况下,在写入之前将所有iov条目移动到单个缓冲区中。 writev
调用来执行不阻塞的部分写入。据我所知,这个问题在一般情况下是不可能解决的。 我不确定第3点,但在阅读时肯定存在相反的方向。如果终端有一些可用数据(短于IOV的总长度),并且后面带有EOF指示符,则在循环中调用
read
可能会阻塞。在这种情况下,调用readv
应该立即返回并部分读取。但是,由于Linux中的错误,终端上的readv
实际上被实现为内核空间中的read
循环,并且确实表现出此阻塞性错误。在实现musl的stdio时,我不得不解决这个错误:http://git.etalabs.net/cgi-bin/gitweb.cgi?p=musl;a=commit;h=2cff36a84f268c09f4c9dc5a1340652c8e298dc0
要回答问题的最后一部分:
在所有情况下,一致的
writev
实现将是单个syscall。深入了解如何在Linux上实现它:对于普通文件和大多数设备,底层文件驱动程序具有直接实现iov-style io的方法,而没有任何内部循环。但是Linux上的终端驱动程序已经过时并且缺乏现代的io方法,导致在终端上运行时内核回退到writev
/readv
的写/读循环。关于c - 列表I/O writev在内部如何工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9336572/