2009-09-01 12 views
30

std :: setのスレッドの安全性に関する質問がありました。C++のstd :: setはスレッドセーフですか?

私が知る限り、私はセットを反復してメンバーを追加/消去することができ、イテレータを無効にしません。

しかし、次のシナリオを検討:

  • スレッド「」のshared_ptrのセットを反復処理<タイプ>
  • スレッド「B」は時折、このセットに項目を追加します。

プログラムの実行中にsegfaultsが発生しましたが、なぜこのようなことが起こるのかわかりません。スレッドの安全性の欠如は原因ですか?

答えて

9

STLコンテナのどれもスレッドセーフではないため、特にstd::setはスレッドセーフではありません。

あなたのケースでは、問題は実際にはスレッドの安全性でさえありません。複数のスレッド間でオブジェクトを共有し、1つのスレッドでオブジェクトを変更するだけです。しかし、既に述べたように、コンテナを変更するとそのイテレータは無効になります。これが同じスレッドまたは別のスレッドで発生するかどうかは、依然としての同じコンテナであるため、何の影響もありません。

D'oh! §23.1.2.8は挿入がイテレータを無効化しないと述べている。

+9

セットを更新してもイテレータは無効になりません..... –

+0

実際には、標準ではstd :: setに追加または削除するとイテレータが無効にならないことが記載されています明白な例外であると削除される)。 – suszterpatt

+0

コメントをいただき、ありがとうございました。私は実装者の観点から言えば、これは本当に奇妙な要件です。 –

26

STLにはスレッドのサポートが組み込まれていないため、 マルチスレッド環境でSTLを使用するには、独自の同期メカニズムを使用してSTL コードを拡張する必要があります。例えば

はここを見て:link text

セットはコンテナクラスですので、MSDNは、コンテナのスレッドの安全性について言いたいことは次の通りです。

単一のオブジェクトは、複数のスレッドからの読み取りにスレッドセーフです。例えば、オブジェクトAが与えられると、スレッド1からAを、スレッド2からAを同時に読み出すことは安全である。

1つのスレッドによって1つのオブジェクトが書き込まれている場合、同じスレッドまたは他のスレッド上のそのオブジェクトに対するすべての読み取りと書き込みを保護する必要があります。たとえば、オブジェクトAを指定すると、スレッド1がAに書き込んでいる場合、スレッド2はAからの読み書きを禁止する必要があります。

あるタイプのインスタンスを読み書きすることは安全ですスレッドは、同じ型の別のインスタンスに読み書きしています。たとえば、同じタイプのオブジェクトAとBを指定すると、Aがスレッド1に書き込まれ、Bがスレッド2で読み込まれている場合は安全です。

+8

実際には、set自体を拡張するのではなく、std :: setを含むスレッドセーフなクラスを作成する方が簡単です。方法が少なくて済む。 – Kieveli

+4

@Kieveli +1しかし、バックドアをセットに戻さないように注意しなければなりません。また、セットイテレータの上に独自のイテレータを書く必要がありますので、インクリメント/デクリメントはスレッドセーフです。スレッドセーフセットもラッパーも実装されていません... –

+0

MSDNの引用へのリンクを提供できますか? NEVERMIND:http://msdn.microsoft.com/en-us/library/c9ceah3b(v=VS.100).aspx –

19

Dinkumware STL-ドキュメントには、そのトピックに関する次の段落が含まれています。おそらく(本文に示されているように)ほとんどの実装で有効です。例えばSTLなどの標準C++ライブラリ で定義されたコンテナオブジェクト、テンプレート クラスのbasic_stringの コンテナとオブジェクトについて

、この 実装はSGI STLため綴ら広く 採用プラクティス以下:

複数のスレッドが同じコンテナオブジェクトを安全に読み取ることができます。 ( nunprotected可変サブオブジェクトは 内のコンテナオブジェクトがある。)

2つのスレッドが安全に異なるコンテナが同じタイプの オブジェクトを操作することができます。 (コンテナ型内には 保護されていない共有静的オブジェクト はありません。)

少なくとも一つのスレッドがオブジェクトを変更 ある場合は、コンテナ オブジェクトへの同時アクセスから保護しなければなりません。 (例えば として明らか 同期プリミティブ、Dinkumスレッドライブラリのもの、 コンテナ オブジェクトによって打倒されない。)

したがって、試みは、容器 オブジェクトに対するアトミック操作であること を確実にするために行われませんスレッドセーフです。共有されたコンテナ オブジェクトは、 でスレッドセーフであるオブジェクトを適切なレベルの細かさにするのに十分なほど簡単に です。

1

簡単な説明:スレッドAがイテレータをコンテナ内を移動している場合は、コンテナの内部を調べています。スレッドBがコンテナを変更した場合(Aが持つイテレータを無効にしない操作であっても)、Bがコンテナ内部を欺くことになり、(一時的に)無効な状態になる可能性があるため、スレッドAに問題が発生する可能性があります。これはスレッドAのクラッシュを引き起こします。

問題は反復子自身ではありません。それは、あなたが困ってしまう位置を見つけるためにコンテナのデータ構造が必要なときです。

そのように単純です。

0

はい。この状況を処理する1つの方法は、同じセットオブジェクトにアクセスする前に、各スレッドが共有ミューテックスをロックするようにすることです。 RAII技術を使用して、ミューテックスをロックおよびロック解除することを確認してください。

0

挿入を実行すると、ベクタが元のメモリを再割り当てすることがありますが、イテレータは以前の(ただし無効な)メモリアドレスを引き続き指している可能性があり、セグメントフォルトにつながります。

関連する問題