2012-05-13 10 views
4

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

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++: 
} 

答えて

3

OP "イテレータ(アプローチ2)の代わりにインデックス(アプローチ1)を使用してコンテナにアクセスすることは、スレッドを安全にしますか?

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

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

多くの時間と不満を解消するために、多数のレディロールソリューションがあります。

concurrent_vectorのようなスレッドセーフコンテナに付属のインテルスレッディングビルディングブロック(TBB)。

  • インデックスによるランダムアクセス:

    http://threadingbuildingblocks.org/

    concurrent_vectorは、以下の機能を備えたコンテナです。最初の要素のインデックスはゼロです。

  • 複数のスレッドでコンテナを拡張し、新しい要素を同時に追加できます。既存のイテレータやインデックスを無効にしないコンテナを育てる
  • 。*

OP "何のパフォーマンスは?"

わからない。異なるコンパイラを使用する異なるシステムではパフォーマンスは異なりますが、選択肢に影響を与えるのに十分な大きさではありません。

3

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

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

+0

+1 C/C++の標準ライブラリでは、スレッドセーフであるとはみなされません。しかし、POSIXで定義された関数はスレッドセーフであると定義されています。 – sj755

+4

@ seljuq70:あなたの声明は間違っています。最新のstnadards更新がリリースされる前は本当でしたが、CとC++の両方でスレッドセーフの保証が提供されています。あなたが望むものではないかもしれませんが、それはライブラリの構造がスレッドセーフでないことを意味するものではありません。さまざまなクラスは実際には多くの人がスレッドセーフであると誤解しているように見えるモニター(ほとんどの場合)です。 –

+0

@DietmarKühl私のメモを見て、それはあなたが絶対に正しいと思われる。ほぼすべてのシステムとライブラリ関数はスレッドセーフであると考えられています。また、すべてのPOSIX関数がスレッドセーフであるというのは間違っていました。例えば、readdirとstrerrorはスレッドセーフであるとは限りません(私は可能であると想定していますが)。 – sj755

4

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

  1. それがあります要件はコンテナオブジェクトごとに
あること
  • コンテナを修正する一つのスレッドがある場合(読み取りまたは書き込み)にアクセスする他のスレッドがあってはならない
  • 複数の同時の読者を持ってOK

    これは、複数のスレッドからアクセスされるコンテナが正しく処理されることを保証するために、コンテナの外部のメカニズムを使用する必要があることを意味します。たとえば、ミューテックスやリーダライタロックを使用できます。もちろん、ほとんどの時間コンテナは1つのスレッドからのみアクセスされ、物事はロックされずに正常に機能します。

    Explict Lockを使用しないと、インデックスやイテレータを使用するかどうかに関係なく、データ競合が発生し、動作は未定義です。

  • +0

    Approach1とApproach2のパフォーマンスについてコメントできますか? – sank

    +1

    どちらが速いのですか?それらの中の一つ。プラットフォーム、コンパイラ、コンパイラのバージョン、コンパイラフラグ、おそらく月のフェーズによって変わります。プロファイルする必要があります。インデックスとイテレータの使用の選択は、アクセスされるオブジェクトの局所性に比べておそらく限界があることに注意することは重要です。 –

    0

    あなたのアルゴリズムは固定サイズの配列で動作しますか?

    理由スレッドセーフなロックフリーの方法で複数のスレッドを(ほとんどの種類の)コンテナを変更する唯一の方法は、論理的にコンテナ自体を不変にすることです。つまり、CONTAINERはスレッド内で変更されることはなく、その中の要素だけが変更されます。列車のボックスカーの内部を混乱させることと、実際にトラックを移動する列車から箱車全体を取り除くこととを比較して、実際に&を追加することとの違いを考えてください。要素に干渉しても、そのデータに対する操作で特定の制約が満たされている場合にのみ安全です。

    良いニュースは、ロックは常に世界の終わりではないということです。複数の実行コンテキスト(スレッド、プログラムなど)が同じオブジェクトに同時に当たることがある場合、それらはしばしば唯一の解決策です。

    関連する問題