目次 - SDL 3.0 API(機能別) - 非同期I/O

非同期I/O

概要

SDLはI/Oを非同期に行う手段を提供している. これは, アプリケーションのファイルの読み込みや書き込みを, 実際にデータを転送するまで待たせずに行うことができる. 入力力を要求する関数は, 完了するまでブロックすることはしない.

代わりに, データはバックグラウンドで転送され, アプリケーションは空いた時間に結果をチェックする.

ファイルの読み書きを同期的に行うよりも複雑になるが, より効率的で, ハードディスクが追い付けない場合でもフレームレートを落とさず処理すること等ができる.

一般的な非同期I/Oの使い方:

全ての動作はシングルスレッドでブロックなしで行われるが, バックグラウンドスレッドでスリープして新しい結果が届くまでキューを待たせることもできる.

そして, 同期処理のSDL_LoadFileに対応したSDL_LoadFileAsyncが便利な関数として提供されている. これはバッファの確保し, 全ファイルデータを読み込み, 終端にNULを追加する. これも結果は後でチェックする.

この機能のために, SDLは背後で動作環境の新しい効率的なAPIを使用している. 例えば, Linuxのio_uringや, Windows 11のIoRingである. これらの機能が使えない場合, SDLはアプリケーションをブロックせずに同期処理を管理する別のスレッドプールに作業を渡す.

効率のよい方法

単純な非ブロッキングI/O(ディスクの回転を待つことでフレームを失わせないように, 単に準備ができたらデータが欲しいようなアプリケーション)は, どのような場合でもうまく使うことができる. この場合, 単に必要なときSDL_ReadAsyncIOや, あるいはSDL_LoadFileAsyncを呼ぶ. 1フレームごとに, SDL_GetAsyncIOResultを呼んでタスクの完了をチェックし, 届いたデータの処理を行えばよい.

1つのプログラムの2か所でI/Oが必要な場合, それぞれにキューを生成することは正しい. これにより, 一方が誤って他方の完了したタスクを消費することを防ぐことができる. それぞれのキューに資源が必要となるが, 大きなコストではない. しかし, タスクごとにキューを作ってはならない. 1つのキューに多くのタスクを入れる方がよい. タスクは, 要求した順番ではなく, 完了した順番に報告される. そのため, 一般的にはタスクをどの順序で開始するかは問題にならない.

1つの非同期I/Oキューは, 複数のスレッドで共有でき, また1つのスレッドで複数のキューを持つこともできる. しかし, 最も効率がよい(効率のみを目標とするならば)のは, 1つのスレッドには1つのキューとして, 複数スレッドで平行して作業を行い, 各スレッドで開始し消費するタスクを各キューに渡す方法である. 新しいインターフェースが使える現代的な環境では, この方法で同じキューへのアクセスによるスレッド間の競合がなく, ストレージからアプリケーションへの可能な限り効率的なデータの流れを維持することができる.

書き込まれたデータは, クローズを行うタスクが完了するまで物理メディアに書き込まれる保証はない. SDL_CloseAsyncIOのflush引数を真にして呼び出し成功しても, 掃き出されていなければ不運なタイミングによる電源断などでデータが失われる可能性がある. しかし, アプリケーションの必要に応じて, 掃き出しには時間がかかる場合や不要な場合もある.

関数

  1. SDL_AsyncIOFromFile
  2. SDL_CloseAsyncIO
  3. SDL_CreateAsyncIOQueue
  4. SDL_DestroyAsyncIOQueue
  5. SDL_GetAsyncIOResult
  6. SDL_GetAsyncIOSize
  7. SDL_LoadFileAsync
  8. SDL_ReadAsyncIO
  9. SDL_SignalAsyncIOQueue
  10. SDL_WaitAsyncIOResult
  11. SDL_WriteAsyncIO

  1. SDL_AsyncIO
  2. SDL_AsyncIOQueue

構造体

  1. SDL_AsyncIOOutcome

列挙体

  1. SDL_AsyncIOResult
  2. SDL_AsyncIOTaskType

SDL Wikiへのリンク

SDL3/CategoryAsyncIO - SDL Wiki