[12]APUE:高级 I/O

一、分散聚离(向量) I/O

[a] readv / writev

#include <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)
/*成功返回已操作的字节数量,出错返回 -1*/
struct iovec {
    void    *iov_base; //缓冲区地址
    size_t    len;
} 
  • 用于针对多个不连续缓冲区同时写入写出的原子操作,减少了系统调用次数,通常提供比线性 I/O 更高的效率与性能
  • 参数 iov 是指向 iovec 结构体的数组的指针,当其元素数量 <=8 时,系统通常会在栈上分配空间以优化性能
  • 按数组元素順序依次读写

[b] 样例

#include <sys/uio.h>
#include <fcntl.h>
#include <stdio.h>
#define N0 10
#define N1 20
#define N2 30

int
main(void)
{
    char *file = "/var/log/messages";
    int fd, i;
    char test0[N0], test1[N1], test2[N2];
    struct iovec iov[3];

    fd = open(file, O_RDONLY);
    if (-1 == fd) 
    {
        perror("open");
    }
    
    iov[0].iov_base = test0;
    iov[0].iov_len = N0;
    iov[1].iov_base = test1;
    iov[1].iov_len = N1;
    iov[2].iov_base = test2;
    iov[2].iov_len = N2;
    
    i = readv(fd, iov, 3);
    if (-1 == i)
    {
        perror("readv");
    }
    ((char *)(iov[0].iov_base))[N0 - 1] = '
';
    ((char *)(iov[1].iov_base))[N1 - 1] = '
';
    ((char *)(iov[2].iov_base))[N2 - 1] = '
';
    i = writev(1, iov, 3);
    if (-1 == i)
    {
        perror("writev");
    }
}
fh@Server ~/APUE$ ./a.out 
Dec 16 18
00:00 Server newsys
og[865]: logfile turned over  

二、存储影射(内存影射)

[a] mmap / munmap

#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) //成功返回分配到的内存位置(指针),出错返回 MAP_FAILED
int munmap(void *addr, size_t len) //成功返回 0,出錯返回 -1
  • mmap:
    • addr 通常设置为 0,表示由系统自动分配内存
    • len 指定要 map 的内存区域字节长度
    • prot 指定影射内存区的权限,由 PROT_READ / PROT_WRITE / PROT_EXEC 按位 OR 賦值,不能与 open 调用的权限位或其它系统权限策略冲突
    • flags 常用选项:MAP_SHARED / MAP_PRIVATE,前者对影射内存区的更改会写入文件,后者采用写时复制(COW)创建内存副本,不修改源文件
    • fd 是与将要 map 的目标文件相关联的文件描述符
    • offset 指定从目标文件 map 的起始位置(距离文件开头的偏移量),如指定为 100,意为从第 100 字节开始 map 长度为 len 字节的内容到 mmap 函数返回的指针所指向的内存区
  • mmap 函数分配出的内存都是以页为单位对齐的,通常适用于分配较大的内存;malloc 函数的分配方法通常是小内存(<128KB)在堆上分配,大内存使用内存影射
  • 运行时获取页大小:sysconf(_SC_PAGESIZE)
  • 内存影射优点:
    • 直接操作内存,不使用缓冲区,避免了多余的数据复制
    • 不调用 read、write 等系统调用,无上下文切换的开销
    • 多个进程 map 同一文件的同一区段的时候,数据会在所有进程间共享
    • 文件偏移只需要移动指针,无须再调用 lseek
  • 内存影射的缺点:
    • 映射区域的大小总是页大小的整数倍,对于小文件会造成内存浪费
    • 创建和维护映射及相关内核数据结构会有一定的开销,但相对于其节省的开销,是可以忽略的

[b] msync / mprotect

#include <sys/mman.h>
int msync(void *addr, size_t len, int flags) //成功返回 0,出错返回 -1
int mprotect(const void *addr, size_t len, int prot) //同上 
  • msync 相当于专门用于内存影射的 fsync,flags 可用选项有 MS_SYNC / MS_ASYNC,前者只有当数据真正已写回磁盘,msync 函数才返回,后者立即返回,数据何时真正写回磁盘,由系统调度
  • mprotect 用于更改指定内存区域的权限,通常是先前用 mmap 分配的区域,但 Linux 可以用于更改任意用户空间可用的内存区域

三、POSIX I/O 提示 

#include <fcntl.h>
int posix_fadvise(int fd, off_t offset, off_t len, int advice) //成功返回 0,出错不设置 errno 
    The behavior is specified by the advice parameter and may be one of:

     POSIX_FADV_NORMAL      Tells the system to revert to the default data
                            access behavior.

     POSIX_FADV_RANDOM      Is a hint that file data will be accessed
                            randomly, and prefetching is likely not
                            advantageous.

     POSIX_FADV_SEQUENTIAL  Tells the system that file data will be accessed
                            sequentially.  This currently does nothing as the
                            default behavior uses heuristics to detect
                            sequential behavior.

     POSIX_FADV_WILLNEED    Tells the system that the specified data will be
                            accessed in the near future.  The system may
                            initiate an asynchronous read of the data if it is
                            not already present in memory.

     POSIX_FADV_DONTNEED    Tells the system that the specified data will not
                            be accessed in the near future.  The system may
                            decrease the in-memory priority of clean data
                            within the specified range and future access to
                            this data may require a read operation.

     POSIX_FADV_NOREUSE     Tells the system that the specified data will only
                            be accessed once and then not reused.  The system
                            may decrease the in-memory priority of data once
                            it has been read or written.  Future access to
                            this data may require a read operation. 
  • 指定恰当的预读策略,可大幅提升普通文件 I/O 性能
  • offset 为 0 时,提示从文件开头预读,当 offset 与 len 同时为 0 时,表示整个文件 
原文地址:https://www.cnblogs.com/hadex/p/6128443.html