该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,则管道写入需要是原子的,但循环将破坏原子性要求.除了在写入总长度最多之前将所有iov条目移动到单个缓冲区之外,此问题无法解决PIPE_BUF.writev调用将需要执行部分写入而不会阻塞.据我所知,在一般情况下,这个问题是不可能解决的.我不确定第3点,但在阅读时肯定存在于相反的方向.read如果终端具有一些可用的数据(短于总的iov长度),然后是EOF指示符,则可以阻止循环调用; 在这种情况下,调用readv 应立即返回部分读取.但是,由于Linux中的错误,readv终端实际上是作为read内核空间中的循环实现的,并且它确实表现出这种阻塞错误.我不得不在实现musl的stdio时解决这个bug:
http://git.etalabs.net/cgi-bin/gitweb.cgi?p=musl;a=commit;h=2cff36a84f268c09f4c9dc5a1340652c8e298dc0
要回答问题的最后部分:
或者
writev在一次I/O调用中将所有内容写入文件?
在所有情况下,一致的writev实现将是单个系统调用.深入了解它在Linux上的实现方式:对于普通文件和大多数设备,底层文件驱动程序都有直接实现iov-style io的方法,没有任何内部循环.但在Linux终端驱动程序是非常过时,缺乏现代io的方法,导致内核退却到了读/写循环writev/ readv终端上操作时.
知道代码如何工作的直接方法是阅读源代码.
见http://www.oschina.net/code/explore/glibc-2.9/sysdeps/posix/writev.c
它简单地将alloca()或malloc()作为缓冲区,将所有向量复制到其中,并调用write()一次.
它是如何工作的.没什么神秘的.