まず、について混乱があるのではないかと思いますtbb::concurrent_vector
。std::vector
このコンテナは、スレッドセーフなサイズ変更と似ていますが、内部ストレージレイアウトのため、要素へのアクセスが遅くなります。
あなたはここでそれについてもっと読むことができます。
あなたの場合、あなたが提案した2番目の解決策(x * width + y
インデックス付きの1D配列)のために、私はあなたのアルゴリズムが配列の集中的なマルチスレッドのサイズ変更を含まないと仮定しています。tbb::concurrent_vector
したがって、のようなシングルスレッドコンテナと比較してもメリットはありませんstd::vector
。
スレッドセーフな要素アクセスが保証されていると想定していたと思いますがtbb::concurrent_vector
、そうではありません-docからの引用:tbb::concurrent_vector
::operator[]
指定されたインデックスの要素への参照を取得します。
このメソッドは、呼び出し元のスレッドがそのインデックスをチェックしている限り、同時読み取りに対して、またベクターの拡張中にスレッドセーフです。
配列のサイズを変更しない場合は、最初の部分であるスレッドセーフな同時読み取りのみに関心があります。しかし、std::vectorまたは生のC配列でも同じことができます。一方、どちらもスレッドセーフな任意のアクセス(読み取り/書き込み要素)を提供しません。
ロックを使用して実装するか、これを実行する別のライブラリを見つける必要があります(おそらくstd::vector
、STLPortからですが、よくわかりません)。これは非常に非効率的ですが、2D配列から要素にアクセスするたびに、スレッド同期のオーバーヘッドが発生するためです。正確に何を実装しようとしているのかはわかりませんが、同期に実際の計算よりも時間がかかる可能性があります。
質問に答えるために、シングルスレッド設定でも、ND配列を表すために1D配列を使用することをお勧めします。これは、インデックス(x * width + y)の計算が、真のND配列に必要な追加のメモリアクセスよりも高速であるためです。 。同時ベクトルの場合、これはさらに当てはまります。これは、最良のシナリオ(競合する行アクセスがない)では2倍のロックオーバーヘッドがあり、競合がある場合はさらに多くのオーバーヘッドが発生するためです。
したがって、あなたが提案した2つのソリューションのうち、私は躊躇せずに2番目のソリューションを選択しtbb::concurrent_vector
ます。要素にアクセスするための適切なロックを備えた1D配列(必須ではありません)です。
アルゴリズムとさまざまなスレッドによるアクセスパターンに応じて、画像編集ソフトウェア(gimp、photoshop ...)で使用される別のアプローチはタイルベースです。
template<typename T> struct Tile {
int offsetX, int offsetY;
int width, height;
Not_ThreadSafe_Vector<T> data;
};
ThreadSafe_Vector< Tile<T> > data
Not_ThreadSafe_Vector
要素のアクセスをロックしないコンテナはどこにありますかstd::vector
。ThreadSafe_Vector
スレッドセーフな読み取り/書き込み要素アクセスを備えたコンテナです(!ではありませんtbb::concurrent_vector
)。このように、アクセスパターンにある程度の局所性がある場合(スレッドは、遠くよりも前のアクセスに近い要素にアクセスする可能性が高い)、各スレッドは、ほとんどの単一タイルからのデータを処理するように作成できます。時間、そして別のタイルに切り替えるときだけ同期オーバーヘッドがあります。