1

サイズ変更が必要ない限り、いくつかのセルを読み取り、STL ベクトルの異なるセルに同時に書き込むことが許可されていることを私は知っています。各スレッドが異なるキーにアクセス/挿入することを保証する場合、いくつかのキーの値を同時に取得し、同時に新しいキーと値のペアを Visual C++ 2010 の STL マップに挿入できるかどうか疑問に思っています。

http://www.cplusplus.com/reference/map/map/operator[]/ から:

データ競合:

コンテナーがアクセスされ、変更される可能性があります。この関数は要素にアクセスし、マップされた値を変更するために使用できる参照を返します。他の要素への同時アクセスは安全です。関数が新しい要素を挿入する場合、コンテナー内で範囲を同時に反復することは安全ではありません。

したがって、これは、新しい要素を挿入すると、コンテナーを反復処理できないことを示しています。問題は、別の要素にアクセスするためにコンテナーを反復処理する必要があるかどうかです。それは安全ですか?

コンテナーのサイズが N を超えないことを保証すれば安全でしょうか? 次に、ベクトルのサイズが変更されない限り、ベクトルの内部のように、マップの内部データ構造を事前に割り当てて一定のままにすることができます。

利用可能なマップのスレッドセーフな実装があることは知っていますが、おそらくはるかに遅いので、変更しているコードはアプリのホットスポットであるため、私の場合は標準マップで十分かどうか疑問に思っています。

ありがとう、ミハル

4

1 に答える 1

5

各スレッドが異なるキーにアクセス/挿入することを保証する場合、いくつかのキーの値を同時に取得し、同時に新しいキーと値のペアを Visual C++ 2010 の STL マップに挿入できるかどうか疑問に思っています。

いいえ、許可されていません。検索には、内部データ構造の走査が含まれます ( std::map の場合、内部表現の一般的なアプローチは、Red–black treeのような二分探索木です)。一方、挿入は内部構造を変更します。

同時ルックアップと挿入がスレッドセーフである場合、シングルスレッド環境であっても、アクセスごとに操作の同期コストが高くなり、C++ の原則と矛盾します-「使用しないものに対して支払う」.

MSVC 2010 のスレッド セーフ:

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

そうは言っても、他のスレッドで挿入操作の前に要素への参照が既にある場合、オブジェクトは内部リバランス中に移動されないため、その参照を介して要素にアクセスしても安全です。

ISO C++11 23.2.4/9:

insert メンバーと emplace メンバーは、イテレーターとコンテナーへの参照の有効性に影響を与えません。ererase メンバーは、イテレーターと消去された要素への参照のみを無効にします。


MSVC 2012 (MSVC 2010concurrency::concurrent_unordered_mapではない) には連想コンテナーがあります (順序付けされていないため、 に似ていますstd::unordered_map。つまり、厳密な弱い順序付けではなく、キーのハッシュと等価性が必要です)。

このconcurrent_unordered_mapクラスは、 s 型の要素の可変長シーケンスを制御する同時実行セーフ コンテナーですtd::pair<const _Key_type, _Element_type>。シーケンスは、同時実行セーフな追加、要素アクセス、イテレータ アクセス、およびイテレータ トラバーサル操作を可能にする方法で表されます。


Intel TBBライブラリには同様のコンテナがあります - tbb::concurrent_unordered_map:

同時挿入とトラバーサルをサポートする連想コンテナーのテンプレート クラス。

于 2013-07-11T19:47:58.160 に答える