web-dev-qa-db-ja.com

C ++ std :: setはスレッドセーフですか?

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

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

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

  • スレッド 'A'は、shared_ptr <Type>のセットを反復処理します
  • スレッド「B」は時々このセットにアイテムを追加します。

プログラムの実行中にsegfaultを経験しましたが、なぜこれが起こるのかわかりません。スレッドセーフの不足が原因ですか?

38
Racer

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

たとえば、こちらをご覧ください: リンクテキスト

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

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

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

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

30
Vaibhav

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

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

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

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

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

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

23
RED SOFT ADAIR

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

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

ああ! §23.1.2.8では、挿入によってイテレータが無効になることはありません。

11
Konrad Rudolph

挿入を実行すると、イテレータが以前の(ただし無効な)メモリアドレスをまだポイントしている間に、ベクトルが基になるメモリを再割り当てし、セグメントエラーが発生する可能性があります。

2
user1988707

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

問題はイテレータ自体ではありません。トラブルに巻き込まれた位置を見つけるためにコンテナのデータ構造が必要な場合。

そのような単純な。

2
Michael Kohne

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

1
Brian Neal