TEDIA会員に登録したメールアドレスとパスワードを入力してください

メールアドレス:

     パスワード:


パスワードを忘れた方はパスワードの確認を行ってください。

TEDIA会員へのご登録がお済みで無い方はこちらで登録ができます


>> テクノロジーポータル TEDIA トップページへ戻る <<

Think IT Software Developer's Think IT Find-IT 失敗しないソフト選び Find-IT TEDIA テクノロジーポータル TEDIA インストールマニアックス2008 インストールマニアックス2008

TEDIA SponsorsOpen 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]に至るまで必ずセグメントの順を追って動作します。


前のページ     1    2    3    4    次のページ

Copyright © 2008 Ziff Davis Enterprise, Inc.
Originally appearing in the U.S. Edition of Dev Shed. All Rights Reserved.