マルチスレッディング

GDAL-API: 再入可能だが,スレッドセーフではない

用語 スレッドセーフ または 再入可能 の正確な意味は完全に標準化されていません.ここでは, QTの定義 を使用します. 特に, C関数またはC++メソッドは, 複数のスレッドから同時に呼び出すことができると言われます. しかし 各呼び出しが独自のデータを使用する場合のみ, 再入可能であるとされます.

すべてのGDAL公開C関数とC++メソッドは再入可能ですが, 以下の例外があります:

これらの関数は複数のスレッドから同時に呼び出すべきではありません.また, プログラムの初期化と終了時には, 一般的にこれらの関数をプログラムのメインスレッドから呼び出すのがベストプラクティスです.

特に指定されていない限り, GDAL公開C関数とC++メソッドはスレッドセーフであると仮定してはいけません. つまり, 同じデータインスタンスに対して複数のスレッドから同時にGDAL関数を呼び出すべきではありません. また, 所有関係を通じて密接に関連しているインスタンスに対しても同様です. たとえば, マルチバンドラスターデータセットの場合,同じ GDALDataset インスタンスによって所有されている異なる GDALRasterBand インスタンスに対して同時にGDAL関数を呼び出すことは安全ではありません (各スレッドは代わりに異なるGDALDatasetを操作するべきです). 同様に, 複数の OGRLayer を所有するGDALDatasetの場合も同様です.

その理由は, GDALDatasetやGDALRasterBandのほとんどの実装が状態を持っているためです.GDALDatasetは通常, ファイルハンドルを所有し, それに対してシーク/読み取り操作を行うため,同時アクセスを許可しません. 特定のGDALDatasetに関連するブロックキャッシュ関連の構造はスレッドセーフではありません. ドライバは, さまざまなメタデータにアクセスするための遅延初期化戦略を実装することがよくあり, これらのメタデータにアクセスするためのメソッドが初めて呼び出されたときにのみ解決されます. ドライバはまた, スレッドセーフでないオブジェクトを公開するサードパーティライブラリに依存することがあります.

これらの制限は, CおよびC++のABI, およびすべての言語バインディングに適用されます(特別な注意を払って呼び出しを直列化する場合を除く)

GDALブロックキャッシュとマルチスレッディング

現在のGDALラスターブロックキャッシュの設計では, 複数のデータセットの同時読み取りが許可されています. ただし, 複数のスレッドから複数のデータセットに書き込む場合, ブロックキャッシュメカニズムのグローバル構造体でのロック競合によるパフォーマンス問題が発生する可能性があります.

RAMの断片化とマルチスレッディング

ラスターデータセットの読み取りまたは書き込みを行うマルチスレッディングを含むシナリオは,Linuxのデフォルトの動的メモリアロケータを使用している場合, 高いRAM使用量を引き起こす傾向があることが観察されています. 代替の tcmalloc メモリアロケータを使用すると, 使用される仮想メモリと常駐メモリの量を減らすのに役立ちます.

たとえば, Debian/Ubuntuディストリビューションでは, libtcmalloc-minimal4 パッケージをインストールし, GDALを実行するバイナリを次のように実行することで, これを行うことができます:

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libtcmalloc_minimal.so.4 ./binary

GDALとマルチプロセッシング

GDAL操作の途中でPOSIX fork() APIを呼び出すべきではありません. そうしないと, フォークされたプロセスでミューテックスなどの構造体が永遠にロックされたように見える可能性があります. マルチプロセッシングを行う場合, GDAL操作を行う前にプロセスをフォークすることをお勧めします. 複数のサブプロセスで同じGDALDatasetインスタンスに操作を行うと, 基になるファイルディスクリプタが共有されているため, 一般的に誤った結果になります.