非同期IO

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内検索

非同期IO (Asynchronous I/O) あるいは非ブロッキングIO(non-blocking I/O)とは、入出力の完了を待たずに、システムコールが終了する入出力処理の実装の事である。

概要[編集]

たとえば、ダイレクト・メモリ・アクセスで動作するファイル操作であれば、メインメモリ上に存在するデータに対してDMA転送を開始しても、ディスク上に転送が終了するまで、数msの待ち時間が必要になる。

この間に、コンピュータはマルチタスク処理で多重処理を行うことが出来るが、処理を発行したプロセスタスクは、処理の完了を待たなくてはならない。

しかし非同期IOでは、処理を発行したプロセスやタスクは、入出力処理の完了を待つことなく、自身の処理を進めることが可能になる。

したがって、入出力命令を連続して発行することが可能になり、シングルプロセスのプログラムでも、自身の入出力を多重し、複数の入出力処理を同時並行化できる。

このため、時間制約の厳しい、リアルタイムオペレーティングシステムの入出力システムコールでは、このタイプの実装が多い。

linuxでは、POSIX-XSIあるいはPOSIX 1003.1bの実装が行われている。

使用方法[編集]

基本的な呼び出し方法は、以下のステップである。

(1)実行するシステムコールの内容をリンクリストで記述する。

(2)リンクリストをパラメータとして、非同期システムコールを発行する(呼び出す)。

(3)エラーあるいは、終了しているかどうかを、問い合わせるシステムコールを発行する。

(4)終了待ちシステムコールを発行するか、既に発行したシステムコールをキャンセルするシステムコールを発行する。

組込型RTOSやミニコンピュータでの実装は、非同期システムコール発行時に、システムサービスコールをOSの処理として行うが、UNIXやlinuxの処理では、ユーザスレッドとして処理を行っている実装が多い。

下記の例では、lio_listio(LIO_WAIT,(struct aiocb **)&List[0],DATA_BUF_NUM, &sig);に続いて、aio_suspend((const struct aiocb **)&List[0],DATA_BUF_NUM, &timeout);を実行しているため、実質的にwrite()と同じになる。

linuxでのサンプルプログラム[編集]

/* 非同期IOによるファイル出力の例 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <aio.h>
#include <sys/mman.h>
#define DATA_BUF_SIZE 4096
#define DATA_BUF_NUM 128

int main()
{
   int fd;
   int n,status;
   unsigned char *  Aio_buff[DATA_BUF_NUM];
   struct aiocb Aiocb[DATA_BUF_NUM];
   struct aiocb *List[DATA_BUF_NUM];

   if ((fd = open("datafile",(O_CREAT|O_WRONLY), 0666)) <0)
   {
       exit(1);
   }
   /* リンクリストの作成 */
   for(n=0;n<DATA_BUF_NUM;n++)
   {
        Aio_buff[n] = (unsigned char*)memalign(sysconf(_SC_PAGESIZE),DATA_BUF_SIZE);
        memset((void *)(Aio_buff[n]),n,DATA_BUF_SIZE);/* データはページ単位にnで埋めている */
        Aiocb[n].aio_buf = Aio_buff[n];
        Aiocb[n].aio_offset = (long long)(DATA_BUF_SIZE * n);
        Aiocb[n].aio_nbytes      = (long long)DATA_BUF_SIZE;
        Aiocb[n].aio_fildes     = fd;
        Aiocb[n].aio_reqprio     = 0;
        Aiocb[n].aio_lio_opcode  = LIO_WRITE;
        Aiocb[n].aio_sigevent.sigev_notify = SIGEV_NONE;
        List[n] = &Aiocb[n];
   }
   /* 非同期IOの発行 */
   lio_listio(LIO_WAIT,(struct aiocb **)&List[0],DATA_BUF_NUM, &sig);
   /******/
   /* この間ファイル出力と並行して、別の処理を記述出来る */
   /******/
   /* 非同期IOの終了待ち */
   aio_suspend((const struct aiocb **)&List[0],DATA_BUF_NUM, &timeout);
   /* エラーステータスの確認 */
   for(n=0;n<DATA_BUF_NUM;n++)
   {
        status = aio_error(&(Aiocb[n]));
        if (status) printf("%d is error %d:%s\n",n,status,strerror(status));
   }
   /* 終了ステータスの確認 */
   for(n=0;n<DATA_BUF_NUM;n++)
   {
        status = aio_return(&(Aiocb[n]));
        if (status!=DATA_BUF_SIZE) printf("%d is write error\n",n);
   }
   close(fd);
}