web-dev-qa-db-ja.com

unordered_mapスレッドセーフティ

Boost:threadライブラリを使用して、シングルスレッドプログラムをマルチスレッドに変更しています。プログラムはunordered_mapをルックアップのhasp_mapとして使用します。私の質問は….

一度に多くのスレッドが書き込みを行い、別の多くのスレッドが読み取りを行いますが、読み取りと書き込みの両方を同時に行うことはできません。つまり、すべてのスレッドが読み取りを行うか、すべてのスレッドが書き込みを行います。それはスレッドセーフであり、コンテナはこれのために設計されていますか?そして、そうなるとしたら、それは本当に並行してパフォーマンスを向上させるでしょうか?何らかのロックメカニズムを使用する必要がありますか?

C++標準では動作が未定義になると言われていますが、それだけですか?

更新:インテルのconcurrent_hash_mapについても考えていました。それは良い選択肢でしょうか?

28
questions

STLコンテナは、次のことができることが保証されるように設計されています。

A.複数のスレッドが同時に読み取る

または

B. 1つのスレッドが同時に書き込み

複数のスレッドで書き込むことは、上記の条件の1つではなく、許可されていません。したがって、複数のスレッドを書き込むと、未定義の動作であるデータ競合が発生します。

ミューテックスを使用してこれを修正できます。 shared_mutex(shared_locksと組み合わせて)は、そのタイプのmutexが複数の同時リーダーを許可するため、特に役立ちます。

http://eel.is/c++draft/res.on.data.races# は、さまざまなスレッドでconst関数を同時に使用できることを保証する標準の一部です。 http://eel.is/c++draft/container.requirements.dataraces は、異なるスレッドで安全ないくつかの追加の非const操作を指定します。

46
Lalaland

それはスレッドセーフであり、コンテナはこれのために設計されていますか?

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

何らかのロックメカニズムを使用する必要がありますか?

そうです。ブーストを使用しているので、boost::mutexは良い考えです。 C++ 11にはstd::mutex

C++標準では動作が未定義になると言われていますが、それだけですか?

実際、動作は未定義です。未定義の動作は可能な限り最悪の動作であり、それを示すプログラムは定義上正しくないため、「それだけですか?」という意味がわかりません。特に、誤ったスレッド同期は、多くの場合、診断が非常に困難な方法で、ランダムなクラッシュやデータ破損を引き起こす可能性が高いため、絶対に回避することをお勧めします。

更新:インテルのconcurrent_hash_mapについても考えていました。それは良い選択肢でしょうか?

良さそうですが、自分で使ったことがないので意見を述べることはできません。

8
Mike Seymour

std :: unordered_mapはコンテナの要件を満たしています(ref http://en.cppreference.com/w/cpp/container/unordered_map )。コンテナーのスレッドセーフについては、次を参照してください http://en.cppreference.com/w/cpp/container#Thread_safety

重要なポイント:

  • 「同じコンテナ内の異なる要素は、異なるスレッドによって同時に変更できます」
  • 「すべてのconstメンバー関数は、同じコンテナー上の異なるスレッドによって同時に呼び出すことができます。さらに、メンバー関数begin()、end()、rbegin()、rend()、front()、back()、data() 、find()、lower_bound()、upper_bound()、equal_range()、at()、および連想コンテナを除いて、operator []はスレッドセーフの目的でconstとして動作します(つまり、これらを呼び出すこともできます)同じコンテナの異なるスレッドで同時に実行されます)。」
4
Ida

既存の回答は主なポイントをカバーしています:

  • 地図を読み書きするにはロックが必要です
  • 複数のリーダー/単一のライターのロックを使用して同時実行性を向上させることができます

また、次の点にも注意してください。

  • 以前に取得したイテレーター、またはマップ内のアイテムへの参照またはポインターを使用すると、読み取りまたは書き込み操作としてカウントされます

  • 他のスレッドで実行された書き込み操作は、同じスレッドで実行された場合と同じように、ポインター/参照/イテレーターをマップに無効化する可能性があります。

3
Tony Delroy

Unordered_mapにアクセスするときは、concurrent_hash_mapを使用するか、mutexを使用できます。 intel concurrent_hash_mapの使用に関する問題の1つは、TBBを含める必要があることですが、すでにboost.threadを使用しています。これら2つのコンポーネントは機能が重複しているため、コードベースが複雑になります。

1
Chang

std::unordered_mapは、一部のマルチスレッド状況に適しています。

Intel TBBの他の同時マップ もあります。

  • tbb:concurrent_hash_map。それは挿入/更新のためのきめ細かい、キーごとのロックをサポートします。これは他のいくつかのハッシュマップが提供できるものです。ただし、構文は少し複雑です。 完全なサンプルコード を参照してください。オススメです。
  • tbb:concurrent_unordered_map。これは基本的に同じもので、キーと値のマップです。ただし、それははるかに低いレベルであり、使用するのはより困難です。ハッシャー、等値演算子、アロケーターを指定する必要があります。公式のIntelドキュメントにも、サンプルコードはありません。推奨されません。
0
Contango