异步IO写文件的方法
函数解析:
io_setup函数:
此系统调用用于创建一个同步io环境,可以同时处理maxevents个操作,ctxp必须初始化为0,io_setup会自动分配填充空间,所以,调用后一定要掉用io_destroy进行释放掉。
返回值:
成功为0,失败为以下值
EAGAIN:maxevents已经超过个系统用户的限制,即文件/proc/sys/fs/aio-max-nr中的数字
EFAULT:分配给ctxp的指针无效
EINVAL:ctxp未初始化为0或者maxevents超限。
ENOMEM:内核资源不足。(说明系统压力大)
ENOSYS:未实现此系统调用
io_destroy函数:
释放io_setup创建的异步io环境,系统调用将尝试取消针对ctx_id的所有未完成的异步I/O操作,阻塞在不能不取消的操作上直到操作完成。
返回值:
成功为0,失败为以下值
EFAULT:分配给ctxp的指针无效
EINVAL:分配给ctxp的指针无效
ENOSYS:未实现此系统调用
io_submit函数:提交事件
将ios设置的事件,提交到ctx队列中,等待事件排队处理。
返回值:
成功:0~nr
EAGAIN:系统内资源不够用。
EBADF:提交的文件描述符不对,可能是不支持异步操作的文件描述符或者无用已关闭的文件描述符。
EFAULT:某一部分指针无效
EINVAL:参数有问题,检查参数设置。
io_cancel函数:
io_cancel()系统调用试图取消以前用io_submit(2)提交的异步I/O操作。iocb参数描述要取消的操作,ctx参数是提交操作的异步环境上下文。如果操作被成功取消,则事件将被复制到由结果指向的内存中,而不会被放到完成队列中。
返回值:
成功0,失败如上
io_getevents函数:
io_getevents系统调用读取ctx异步环境中至少min_nr至多nr个事件,(前提是timeout为NULL阻塞到至少符合条件数目的事件,如果设置超时,则在一定的时间后返回)
返回值:成功则为完成的事件,0则表示没有完成的事件。失败如上。
代码示例(用来测试异步IO落盘速度)
#include <stdio.h> #include <time.h> #include <pthread.h> #include <unistd.h> /* for syscall() */ #include <sys/syscall.h> /* for __NR_* definitions */ #include <linux/aio_abi.h> /* for AIO types and constants */ #include <fcntl.h> /* O_RDWR */ #include <string.h> /* memset() */ #include <inttypes.h> #include <sys/time.h> #include <stdlib.h> #define COUNT_PTHREAD 8 #define value_SIZE 4*1024*1024UL #define COUNT_VALUE 256 #define COUNT_LOOP 10 static uint8_t * value = NULL; inline int io_setup(unsigned nr, aio_context_t *ctxp) { return syscall(__NR_io_setup, nr, ctxp); } inline int io_destroy(aio_context_t ctx) { return syscall(__NR_io_destroy, ctx); } inline int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) { return syscall(__NR_io_submit, ctx, nr, iocbpp); } inline int io_getevents(aio_context_t ctx, long min_nr, long max_nr, struct io_event *events, struct timespec *timeout) { return syscall(__NR_io_getevents, ctx, min_nr, max_nr, events, timeout); } static uint32_t get_now_time(char * data ,uint32_t channle_id) { static uint32_t cnt = 0; struct timeval tv; char time[60]={0}; gettimeofday(&tv, NULL); strftime(time,60,"%Y-%m-%d-%H-%M-%S",localtime(&tv.tv_sec)); sprintf(data,"/data/brickmd0p1/CH%d-%s-%3d-%d.dat",channle_id,time ,(int)(tv.tv_usec / 1000),cnt++); printf("get_now_time\n"); return 0; } int * openfile(void) { int i; char value[100] = {0}; int fd[COUNT_PTHREAD]; fd = (int *)malloc(sizeof(int) * COUNT_PTHREAD); if(fd == NULL) return NULL; for(i = 0; i < COUNT_PTHREAD;i++ ) { get_now_time(value,i); fd[i] = open(value,O_WRONLY | O_CREAT,777); if(fd[i] < 0) { printf("open file faild\n"); return NULL; } } return fd; } void * write_file(void *s) { int i; int ret; aio_context_t ctx; struct iocb cb; struct iocb *cbs[1]; int * fd = NULL; if(fd = openfile() ,fd == NULL) { return NULL; } ctx = 0; ret = io_setup(256, &ctx); if (ret < 0) { perror("io_setup error"); return NULL; } /* setup I/O control block */ memset(&cb, 0, sizeof(cb)); cb.aio_fildes = *(int*)s; cb.aio_lio_opcode = IOCB_CMD_PWRITE;/* command-specific options */ cb.aio_buf = (uint64_t)value; cb.aio_offset = 0; cb.aio_nbytes = value_SIZE; cbs[0] = &cb; for(i = 0; i < COUNT_VALUE;i++) { ret = io_submit(ctx, 1, cbs); if (ret != 1) { if (ret < 0) perror("io_submit error"); else fprintf(stderr, "could not sumbit IOs"); return NULL; } cb.aio_offset += value_SIZE; } ret = io_destroy(ctx); if (ret < 0) { perror("io_destroy error"); return NULL; } } int main(void) { struct timeval start_t; struct timeval end_t; double total_t; uint32_t i =0; uint8_t * value1 = NULL; long count = 0; uint32_t size = 0; pthread_t pthread_id[COUNT_PTHREAD]; value1 = (uint8_t *)malloc(value_SIZE); if(value1 == NULL) { printf("malloc faild\n"); return -1; } value = value1; memset(value,0,value_SIZE); for(i=0;i<value_SIZE;i++) { value[i]=i%10+48; } gettimeofday(&start_t,NULL); for(i = 0; i < COUNT_PTHREAD; i++ ) { pthread_create(&pthread_id[i], NULL, write_file,&fd[i]); } for(i = 0; i < COUNT_PTHREAD; i++ ) { pthread_join(pthread_id[i], NULL); } gettimeofday(&end_t,NULL); if(end_t.tv_usec >= start_t.tv_usec) total_t = (double)(end_t.tv_sec - start_t.tv_sec)+(double)(end_t.tv_usec-start_t.tv_usec)/1000000.0 ; else total_t = (double)(end_t.tv_sec - start_t.tv_sec-1)+(double)(end_t.tv_usec+1000000.0-start_t.tv_usec)/1000000.0 ; printf("RECV 0 CH:--------Speed:---%lf MB/S---------\n"\ , (double) value_SIZE * COUNT_PTHREAD * COUNT_VALUE/ total_t/1024/1024); for(i = 0; i < COUNT_PTHREAD; i++ ) { close(fd[i]); } free(value1); }