41

std::setのスレッドセーフについて質問があります。

私の知る限り、セットを反復処理してメンバーを追加/消去することができますが、それによって反復子が無効になることはありません。

ただし、次のシナリオを検討してください。

  • スレッド「A」は、shared_ptr<Type>のセットを繰り返し処理します
  • スレッド「B」は、このセットにアイテムを追加することがあります。

プログラムの実行中にsegfaultが発生しましたが、なぜこれが発生するのかわかりません。スレッドセーフの欠如が原因ですか?

4

6 に答える 6

32

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

たとえば、ここを見てください:リンクテキスト

setはコンテナクラスであるため、MSDNはコンテナのスレッドセーフについて次のように述べています。

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

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

別のスレッドが同じタイプの別のインスタンスに対して読み取りまたは書き込みを行っている場合でも、あるタイプの1つのインスタンスに対して読み取りおよび書き込みを行うのは安全です。たとえば、同じタイプのオブジェクトAとBが与えられた場合、Aがスレッド1で書き込まれ、Bがスレッド2で読み取られている場合は安全です。

于 2009-09-01T12:13:56.433 に答える
24

Dinkumware STL-Documentation には、そのトピックに関する次の段落が含まれています。おそらく(テキストに示されているように)ほとんどの実装で有効です。

標準 C++ ライブラリで定義されているコンテナ オブジェクト (STL コンテナやテンプレート クラス basic_string のオブジェクトなど) の場合、この実装は、SGI STL で詳しく説明されている広く採用されているプラ​​クティスに従います。

複数のスレッドが同じコンテナー オブジェクトを安全に読み取ることができます。(コンテナー オブジェクト内には、保護されていない変更可能なサブオブジェクトがあります。)

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

少なくとも 1 つのスレッドがオブジェクトを変更している場合は、コンテナー オブジェクトへの同時アクセスから保護する必要があります。(Dinkum Threads Library にあるものなどの明らかな同期プリミティブは、コンテナー オブジェクトによって覆されることはありません。)

したがって、コンテナー オブジェクトに対するアトミック操作がスレッド セーフであることを保証する試みは行われません。しかし、適切な粒度レベルでスレッド セーフな共有コンテナー オブジェクトを作成するのは簡単です。

于 2009-09-01T13:10:26.393 に答える
12

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

ただし、あなたの場合、問題は実際にはスレッドセーフではありません。オブジェクトを複数のスレッド間で共有し(細かく)、1つのスレッドで変更するだけです(細かくも)。しかし、すでに述べたように、コンテナを変更するとそのイテレータが無効になります。これが同じスレッドで発生するか、別のスレッドで発生するかは、同じコンテナであるため、重要ではありません。

D'oh!§23.1.2.8は、挿入によってイテレータが無効にならないことを示しています。

于 2009-09-01T12:03:41.847 に答える
2

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

于 2013-01-17T22:14:52.247 に答える
2

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

問題はイテレータ自体ではありません。問題が発生する位置を見つけるためにコンテナのデータ構造が必要な場合です。

そのような単純な。

于 2009-09-01T13:57:45.713 に答える
1

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

于 2009-09-01T18:11:57.760 に答える