前言
根據上文我們學習到的使用者空間的IO緩沖區,作業系統為了減少系統調用的次數,節省系統開銷,提出了使用者空間的IO緩沖區,即為使用者空間的檔案讀寫開辟一段可以利用
setvbuf
配置大小的記憶體空間來作為檔案IO緩沖區。
描述
為了在以上IO緩沖區的基礎上更進一步得減少系統調用的次數,提出了分散/聚合IO技術,總體上是使用了單個向量的IO操作代替了多個向量的IO操作。
讀文多個件的時候将從page cache中讀到的内容先讀入到一個IO緩沖區資料結構中,再由一個緩沖區分别分散傳回到多個檔案緩沖區中;寫檔案的過程與讀檔案的過程剛好相反,即将多個檔案緩沖區的内容聚合寫到一個緩沖區中,寫入page cache中,進而更高得提升系統調用效率。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5SO0IzN4gTYkFzMyY2M4QjNzYzXyAjNxETM0AzLcFTMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
實作
實作
scatter-gather
技術的系統調用原型如下:
- 頭檔案
<sys/uio.h>
-
函數使用:
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
-
函數參數
fd
:打開的檔案描述符
: IO向量資料結構内容如下,每個結構體成員代表一個buffer:iov
struct iovec {
void *iov_base; /* Starting address */
size_t iov_len; /* Number of bytes to transfer */
};
iovcnt
:IO向量的個數
這兩個系統調用的底層仍然是使用read/write系統調用,隻是對IO 緩沖區做了聚合,支援多個IO緩沖區内容聚合到同一個IO向量中
代碼如下:
writev.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/uio.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
ssize_t count = 0;
int fd, i = 0;
char *buf[]={"buffer1\n","buffer2\n","buffer3\n"};
fd = open(argv[1], O_WRONLY|O_CREAT, 0666);
if (-1 == fd) {
printf("open failed \n");
_exit(-1);
}
//将三個IO緩沖區的檔案聚合為一個IO向量
struct iovec iov[3];
for (i ; i < 3; ++i) {
iov[i].iov_base = buf[i];
iov[i].iov_len = sizeof(buf[i]) + 1;
printf("iovec[%d] size is %ld \n",i,iov[i].iov_len);
}
//寫入一個檔案
count = writev(fd, iov, 3);
if (-1 == count) {
printf("writev failed\n");
_exit(-1);
}
close(fd);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/uio.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
ssize_t count = 0;
int fd, i = 0;
char buf1[9],buf2[9],buf3[9];
//生成一個檔案,可以傳入聚合IO緩沖區的檔案
fd = open(argv[1], O_RDONLY,0666);
if (-1 == fd) {
printf("open failed \n");
_exit(-1);
}
//對IO向量中的各個IO緩沖區進行位址和内容大小指派
struct iovec iov[3];
iov[0].iov_base = buf1;
iov[0].iov_len = sizeof(buf1);
iov[1].iov_base = buf2;
iov[1].iov_len = sizeof(buf2);
iov[2].iov_base = buf3;
iov[2].iov_len = sizeof(buf3);
//從page cache讀入的一個向量會分散到三個緩沖區中
count = readv(fd,iov,3);
if (-1 == count) {
printf("writev failed\n");
_exit(-1);
}
for (i ; i < 3; ++i) {
printf(" %s",(char *)(iov[i].iov_base));
}
prinft("buf1 %s\n",buf1);
prinft("buf2 %s\n",buf2);
prinft("buf3 %s\n",buf3);
close(fd);
return 0;
}
zhang@ubuntu:~/Desktop/cpp_practice$ ./writev writevfile
iovec[0] size is 9
iovec[1] size is 9
iovec[2] size is 9
zhang@ubuntu:~/Desktop/cpp_practice$ ./readv writevfile
buffer1
buffer2
buffer3
buf1 buffer1
buf2 buffer2
buf3 buffer3