[プログラミング] aio_readを使ったFutureっぽいインタフェースの実装
ネットワークプログラム周りで、aio_read(3)*1を使う必要が出てきたので、軽く調べてみた。
今回やりたかったのは非同期にIOを発行したあとに別処理を行って、その後取得された結果を使うというものだったのでJavaのFurtureっぽいインターフェイスの実装を行ってみた。
Descriptorクラスのread_async(buf , count)を呼ぶとFurtureDescriptor * が返ってくるので、それに対して別処理を行うなどしたあとget()を呼ぶとread(2)の結果に相当する値が返ってくる。
実装は以下
#include <iostream> #include <cstdlib> #include <unistd.h> #include <aio.h> #include <errno.h> using namespace std; class FurtureDescriptor{ public: FurtureDescriptor(struct aiocb * aiocbp) :aiocbp(aiocbp){} ~FurtureDescriptor(){ free(aiocbp); } //I/Oリクエストが完了するまで待機し、その後結果を返す int get(){ int ret = ::aio_suspend(&aiocbp , 1 , NULL); if(ret < 0){ perror("aio_suspend"); return -1; } return ::aio_return(aiocbp); } //I/Oリクエストが完了しているかどうかを返す //エラーの場合もtrueを返す bool isDone(){ int ret = ::aio_error(aiocbp); if(ret == EINPROGRESS){ return false; }else{ return true; } } private: struct aiocb * aiocbp; }; class Descriptor{ public: Descriptor(int fd) :fd(fd){} ~Descriptor(){ ::close(fd); } ssize_t read(void * buf , size_t count){ ssize_t ret = ::read(fd , buf , count); return ret; } //非同期にread(buf,count)をリクエストする //非同期操作中にbufを変更した場合の結果は不定 FurtureDescriptor * read_async(void * buf , size_t count){ struct aiocb * aiocbp = static_cast<struct aiocb *>(malloc(sizeof(struct aiocb))); aiocbp->aio_fildes = fd; aiocbp->aio_buf = buf; aiocbp->aio_nbytes = count; int ret = ::aio_read(aiocbp); if(ret < 0){ perror("aio_read"); return NULL; } return new FurtureDescriptor(aiocbp); } private: int fd; }; #define N (1 << 29) char buf[N]; int main(int argc , char * argv[]){ int fd = open("large.file" , O_RDONLY); if(fd < 0){ perror("open"); exit(1); } Descriptor d(fd); //sync IO { int n = d.read(buf , N); cerr << n << endl; } //async IO { FurtureDescriptor * future = d.read_async(buf , N); //some operation sleep(1); int n = future->get(); cerr << n << endl; delete future; } return 0; }