マルチスレッドのプログラミング

非同期入出力

各スレッドの同期入出力で同じ効果を実現できるため、非同期入出力が必要になることはほとんどありません。ただし、スレッドで実現できない非同期入出力機能もあります。

簡単な例は、ストリームとしてテープドライブへ書き込みを行う場合です。この場合、テープに書き込まれている間は、テープドライブを停止させないようにします。テープに書き込むデータをストリームとして送っている間は、テープは高速で先送りされます。

ストリーミングをサポートするには、カーネル内のテープドライバはスレッドを使用する必要があります。カーネル内のテープドライバは、割り込みに応答するときに、待ち行列に入っている書き込み要求を発行する必要があります。この割り込みは、以前のテープへの書き込み操作が完了したことを示すものです。

スレッドでは、書き込み順序を保証できません。スレッドの実行される順序が不定だからです。たとえば、テープへの書き込み順序を指定することはできません。

非同期入出力操作

#include <aio.h>

int aio_read(struct aiocb *aiocbp);

int aio_write(struct aiocb *aiocbp);

int aio_error(const struct aiocb *aiocbp);

ssize_t aio_return(struct aiocb *aiocbp);

int aio_suspend(struct aiocb *list[], int nent,
    const struct timespec *timeout);

int aio_waitn(struct aiocb *list[], uint_t nent, uint_t *nwait,
    const struct timespec *timeout);

int aio_cancel(int fildes, struct aiocb *aiocbp);

aio_read(3RT)aio_write(3RT) は、概念において pread(2)pwrite(2) に似ています。ただし、入出力操作のパラメータが、aio_read() または aio_write() に渡される非同期入出力制御ブロック (aiocbp) に格納される点が異なります。

    aiocbp->aio_fildes;    /* file descriptor */
    aiocbp->aio_buf;       /* buffer */
    aiocbp->aio_nbytes;    /* I/O request size */
    aiocbp->aio_offset;    /* file offset */

さらに、必要に応じて、「struct sigevent」のメンバーで非同期通知タイプ (一般には、待ち行列に入れられたシグナル) を指定することができます。

    aiocbp->aio_sigevent;  /* notification type */

aio_read() または aio_write() を呼び出すと、入出力操作が開始されます (または、入出力要求が待ち行列に入れられます)。この呼び出しは、ブロックされずに復帰します。

非同期操作の進行中のエラー状態や復帰状態を判定するために、aiocbp の値を aio_error(3RT) および aio_return(3RT) の引数として使用できます。

入出力操作の完了の待機

1 つ以上の未処理の非同期入出力操作の完了を、aio_suspend() または aio_waitn() を呼び出すことによって待機することができます。入出力操作の成功または失敗を判定するには、完了した非同期入出力制御ブロックに対して aio_error() および aio_return() を使用します。

aio_suspend() および aio_waitn() 関数には、呼び出し側の待ち時間を示す timeout 引数があります。NULL ポインタを指定すれば、呼び出し側が無期限に待つという意味になります。値 0 が設定されている構造体を指すポインタは、呼び出し側がまったく待たないという意味になります。

非同期入出力操作を開始し別の処理を行なって aio_suspend() または aio_waitn() で操作の完了を待つことができます。あるいは、aio_sigevent() で指定された非同期通知イベントを発生させて操作の完了を通知するという方法もあります。

最後に、保留状態の非同期入出力操作を取り消すときは、aio_cancel() を呼び出します。この関数を呼び出すときは、入出力操作を開始するために使用された入出力制御ブロックのアドレスを指定します。