4

STL ベクトルを繰り返し処理し、そこから値を読み取っています。このベクトルを変更できる別のスレッドがあります。これで、他のスレッドがベクトルに要素を挿入または削除すると、反復子が無効になります。関連するロックは使用されません。イテレータ (アプローチ 2) の代わりにインデックス (アプローチ 1) を介してコンテナにアクセスするという私の選択は、それをスレッドセーフにしますか? パフォーマンスはどうですか?

struct A{int i; int j;};

アプローチ 1:

   size_t s = v.size();//v contains pointers to objects of type A
    for(size_t i = 0; i < s; ++i)
    {
         A* ptr = v[i];
         ptr->i++;
    }

アプローチ 2:

std::vector<A*>::iterator begin =  v.begin();
std::vector<A*>::iterator end =  v.end();
for(std::vector<A*>::iterator it = begin; it != end; ++it)
{
     A* ptr = *it;
     ptr->i++: 
}
4

4 に答える 4

4

標準ライブラリ コンテナーのスレッド セーフ保証は非常に単純です (これらの規則は C++ 2011 で追加されましたが、基本的に現在のすべてのライブラリ実装はこれらの要件に準拠しており、対応する制限を課しています)。

  1. 複数の同時リーダーを使用しても問題ありません
  2. コンテナーを変更するスレッドが 1 つある場合、コンテナーにアクセス (読み取りまたは書き込み) する他のスレッドはありません。
  3. 要件はコンテナ オブジェクトごとです

事実上、これは、複数のスレッドからアクセスされるコンテナーが正しく処理されることを保証するために、コンテナーの外部の何らかのメカニズムを使用する必要があることを意味します。たとえば、mutex またはリーダーライター ロックを使用できます。もちろん、ほとんどの場合、コンテナーは 1 つのスレッドからのみアクセスされ、ロックがなくても問題なく動作します。

明示的なロックを使用しないと、データの競合が発生し、インデックスまたはイテレータを使用するかどうかに関係なく、動作が未定義になります。

于 2012-05-13T03:32:02.353 に答える
3

いいえ。STL コンテナはスレッド セーフではありません。

ベクトルにアクセスしている間、各スレッド (削除するスレッド/追加するスレッド) に排他的アクセスを提供する必要があります。インデックスを使用している場合でも、i 番目の要素を削除して、取得したポインターを無効にする可能性があります。

于 2012-05-13T02:55:37.943 に答える
3

OP「イテレータ(アプローチ2)の代わりにインデックス(アプローチ1)を介してコンテナにアクセスするという私の選択は、スレッドセーフになりますか?」

いいえ、データ構造への書き込みを開始すると、どちらのアプローチもスレッドセーフではありません。

したがって、データ構造へのアクセスをシリアル化する必要があります。

多くの時間とフラストレーションを節約するために、多くの既製のソリューションがあります。

などのスレッド セーフ コンテナに付属する Intel Threading Building Blocks (TBB) concurrent_vector

http://threadingbuildingblocks.org/

concurrent_vector は、次の機能を持つコンテナーです。

  • インデックスによるランダム アクセス。最初の要素のインデックスはゼロです。
  • 複数のスレッドがコンテナーを拡張し、新しい要素を同時に追加できます。
  • コンテナーを拡張しても、既存の反復子またはインデックスは無効になりません。*

OP「演出は?」

知りません。異なるコンパイラを使用した異なるシステムでの異なるパフォーマンスですが、選択に影響を与えるほど大きくは知られていません。

于 2012-05-26T12:50:37.253 に答える