Linux的异步IO有两种方式,一种是由glibc提供的aio_xxx函数组成的伪异步IO,另一种则是由Linux内核支持的io_xxx系统调用组成的异步IO。在命名的方式上,glibc相应的函数和数据结构均以aio开头,而Linux系统调用及相应的数据结构则以io或io_开头(aio_context_t是一个例外)。以下分别介绍这两种异步IO方式。
一、glibc异步IO
glibc采用多线程同步的方式来实现异步IO,确切地说这并不是真正意义上的异步IO。我们把调用aio_xxx的线程称为主线程,而把实际请求read/write/fsync的线程称为异步IO线程。
(1) int aio_read(struct aiocb *aiocbp);
主线程先将aiocbp->__error_code设为EINPROGRESS,然后把aiocbp挂到aiocbp->aio_fildes的请求队列。这个请求队列是一个优先队列,aio_fildes相同的aiocb按照优先级进行排序。如果不存在为aio_fildes处理的异步IO线程,那么主线程将会创建一个异步IO线程来处理aio_fildes队列中的请求。对每个aiocb,异步IO线程会先尝试使用pread来读取数据,如果pread返回ESPIPE的错误(例如对管道和套接字进行pread操作),它会再次用read系统调用来读取,在这种情况下,aio_offset将会被忽略。当操作成功完成后,异步IO线程将aiocbp->__error_code设成0,并用操作返回的值来设置aiocbp->__return_value。如果操作失败,则把它设成执行pread/read, pwrite/write,或者fsync/fdatasync出错时的errno。如果操作被撤销,则将__error_code设成ECANCELED。
(2)int aio_write(struct aiocb *aiocbp);
这个函数与aio_read类似,不同的是,异步IO线程会先尝试使用pwrite来写入数据,如果pwrite返回ESPIPE的错误(例如对管道和套接字进行pwri