web-dev-qa-db-ja.com

stlベクトルの同時読み取りはスレッドセーフですか?

私は、膨大な数のスレッドが文字列値のセットを反復処理し、それ自体のデータをリストで使用可能なデータと一致させようとするアプリケーションに取り組んでいます。

私は次のユースケースを探しています:

  1. ベクトルは、std :: string型のいくつかの要素で初期化されます。 (オブジェクト名がstrListであるとしましょう)。 strListは、アプリケーションの起動時に初期化されます。
  2. すべてのスレッドはstrListを反復処理して、その値がstrListの少なくとも1つの要素と一致するかどうかを確認します。
  3. StrListを変更しようとするスレッドはなく、読み取り専用オブジェクトとして厳密に使用されます。

それで、同時読み取りがベクターオブジェクトでスレッドセーフかどうか教えてください。私はRHEL6を使用しており、gccバージョンは4.5.xです。

23
Amey Jah

[〜#〜] yes [〜#〜]あなたが言及したシナリオでは、それは完全にスレッドセーフです。


実際、STLはそれを参照する正しい方法ではありません。
それはC++標準ライブラリです。

C++ 03標準では並行性についてはまったく説明されていないため、コンパイラーの実装の詳細として並行性の側面は省略されています。したがって、コンパイラに付属のドキュメントは、並行性に関連する答えを探す必要がある場所です。

ほとんどのSTL実装は、notスレッドセーフではありません。
しかし、複数のスレッドから同じオブジェクトを同時に読み取る場合、STLのほとんどの実装は確かにスレッドセーフです。

参照:

[〜#〜] msdn [〜#〜]は言う:

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

Dinkumware STL-Documentationは次のように述べています:

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

GCCドキュメントは言う:

現在、スレッドセーフのSGI STL定義を使用しています。

STLのSGI実装は、個別のコンテナーへの同時アクセスが安全であり、共有コンテナーへの同時読み取りアクセスが安全であるという意味でのみスレッドセーフです。 複数のスレッドが単一のコンテナーにアクセスし、少なくとも1つのスレッドが書き込みを行う可能性がある場合、ユーザーはコンテナーアクセス中にスレッド間の相互排除を保証する責任があります。

したがって、上記のことから、はい、GCCでは複数のスレッドから同じオブジェクトを同時に読み取ることはスレッドセーフです。

注:GCCの標準ライブラリはSGIのSTLコードから派生したものです。

40
Alok Save

これについては、C++ 0x FDIS(n3290)に具体的な言及があります。

§17.6.5.9データの競合回避

段落全体が興味深いですが、より具体的には:

3 /C++標準ライブラリ関数は、オブジェクトが直接または間接的にアクセスされない限り、現在のスレッド以外のスレッドからアクセス可能なオブジェクト(1.10)を直接的または間接的に変更してはなりません。これを含む、関数の非const引数を介して間接的に。

これは、std::vector<T>cbegincendを安全に呼び出すことができることを意味します。 operator==operator<またはstd::stringを呼び出すだけでなく。

6 /標準ライブラリコンテナまたは文字列メンバー関数を呼び出すことによって取得されたイテレータの操作は、基になるコンテナにアクセスできますが、変更することはできません。

つまり、コンテナを反復処理するだけでは、そのコンテナを変更することはできません。

3 /にも関わらず、イテレータが自分自身を関連付けられるある種の共有レジスタオブジェクトを変更するため、グローバルオブジェクトの余地があるようです。コンテナ(STLデバッグ機能)。私は意味がありません:

7 /オブジェクトがユーザーに表示されず、データの競合から保護されている場合、実装はスレッド間で独自の内部オブジェクトを共有する場合があります。

さもないと。

とにかく、標準はvectorの反復が安全であることを保証します...しかし、実際にオブジェクトを読み取ることに関しては保証しません(それらはあなた自身のものです)。この場合、std::stringが上でカバーされているため、これがカバーされます。

編集: David Hammenが正しく指摘したように、この標準はまだ完全には実装されていません。以前の標準ではスレッドについて説明していませんでしたが、多くのコンパイラはすでに上記の保証を提供しています。 MSVC、gcc、clang、icc、comeauなど... Alsの回答からわかるように、すべてのビッグネームはすでにこの保証を提供しているはずです。

9
Matthieu M.

データの競合回避に関する一般的なルールに加えて、[container.requirements.dataraces]の標準では

-1-データの競合(17.6.5.9)を回避するために、実装では次の関数をconstと見なす必要があります:beginendrbeginrendfrontbackdatafind、_lower_bound_、_upper_bound_、_equal_range_、at、および連想コンテナまたは順序付けされていない連想コンテナを除き、_operator[]_。

したがって、non-const begin()/end()などを呼び出しても、実際に何も変更しない限り、安全です。

2
Jonathan Wakely