Open Source Web Development Tutorials - Dev Shed
Linux I/Oファイルのシステムコール
(2009/03/03公開)
スキャタ/ギャザーI/O
スキャタ/ギャザーI/Oとは、1つのシステムコールによって1つのデータストリームからバッファのベクターへの書き込みを行う、あるいは代わりに、1つのデータストリームからバッファのベクターへの読み出しを行う入出力の方法です。データがバッファの特定のベクターへと分散される(スキャタ)、あるいは、データがバッファの特定のベクターから収集される(ギャザー)ところから、このような名前が付けられました。別名ベクター型(vectored) I/Oとも呼ばれます。これに対し、第2章で解説した標準の読み出し/書き込みシステムコールは、線形型(linear)I/Oです。
線形型I/Oと比較して、スキャタ/ギャザーI/Oには以下のような 利点があります。
自然な操作
必然的に分割されたデータ-例えば、所定のヘッダーファイル-の場合、ベクター型I/Oは直感的に操作できます。
効率性
たった1つのベクター型I/O動作で、複数の線形型I/O動作と同じ作業を達成できます。
性能
ベクター型I/Oを実行すると、システムコールの数が減少するほか、内部要因の最適化によって、線形型I/Oを実行する場合より性能が上昇します。
原子性
複数の線形型I/O動作と異なり、1つのベクター型I/O動作を実行することで、別のプロセスの動作をインターリービングするリスクがありません。
スキャタ/ギャザーI/Oの手法を使わずに、より自然なI/Oの方法と原子性の両方を実現することも可能です。書き込み前は素のベクターを1つのバッファとして連結し、読み出し後は戻されたバッファを複数のベクターに分解する-すなわち、ユーザースペース・アプリケーションを使えば、マニュアル操作で、分散と収集を行えます。しかし、このようなソリューションは効率的でないばかりか、実行も楽しいものではありません。
readv( )とwritev( )
スキャタ/ギャザーI/Oを実行する一対のシステムコールが、POSIX 1003.1-2001によって定義され、Linuxによって実装されています。Linuxでの実装は、前節で列挙したすべての目標を実現します。
以下のとおり、readv()関数は、ファイル記述子fdからiovで記述されるバッファへcountセグメントを読み込みます。
#include <sys/uio.h>
ssize_t readv (int fd,
const struct iovec *iov,
int count);
以下のとおり、writev()関数は、iovで記述されるバッファからファイル記述子fdへcountセグメントを書き込みます。
#include <sys/uio.h>
ssize_t writev (int fd,
const struct iovec *iov,
int count);
readv()関数とwritev()関数は、それぞれ、read()関数およびwrite()関数と同じように動作しますが、複数バッファの読み出しや書き込みを実行する点が異なります。
以下のとおり、各iovec構造は独立した素のバッファを記述しており、これをセグメントと呼びます。
#include <sys/uio.h>
struct iovec {
void *iov_base; /* pointer to start of buffer */
size_t iov_len; /* size of buffer in bytes */
};
複数のセグメントのセットをベクターと呼びます。ベクターに含まれている各セグメントは、データを書き込む/読み込むメモリー内バッファのアドレスと長さを記述します。readv()関数は、iov_lenバイトの各バッファを完全に埋めた後、次のバッファへと進行します。writev()関数は、常に、完全なiov_lenバイトすべてを書き出した後、次のバッファへと進行します。どちらの関数も、iov[0]から開始して次にiov[1]という具合に、iov[count?1]に至るまで必ずセグメントの順を追って動作します。
Copyright © 2008 Ziff Davis Enterprise, Inc.
Originally appearing in the U.S. Edition of Dev Shed. All Rights Reserved.








