0

重複の可能性:
STL ベクトルとスレッドセーフ

簡単な例:

struct A {
  int a;
  void set_a (int x)
  {
    ...  // line-1
    ...  // line-2
    this->a = x;  // line-3
  }
};
...
vector<A> v;  // somewhere

がスレッドv1 とスレッド 2 で共有されているとします。v.set_a()常にスレッド 1 とv.push_back()スレッド 2 で呼び出されます。したがって、スレッドセーフの問題はありません。

以下の一連のイベントで何が起こるか:

  1. スレッド 1 呼び出しv.set_a()
  2. 行 3 の前に、スレッド 2 はベクトル ( push_back()resize()、...)のサイズを変更します。
  3. 現在の場所に十分な連続メモリがないvため、別の場所に移動する必要があります

未定義の動作につながりますか? はいの場合、そのようなシナリオの最もエレガントなソリューションは何ですか?

4

2 に答える 2

3

ベクトルのサイズ変更がスレッドセーフであると言うことは何もないので、そうではないと想定する必要があります。あなたの例では、多くの非不可分操作に依存しているので、確かに問題が予想されます。エレガントな解決策は、スレッドセーフなバージョンでラップすることです。

于 2012-07-05T05:53:37.647 に答える
2

標準 (C++11、および以前の Posix) は、これについて非常に明確です。オブジェクト (ベクトル) を 1 つのスレッドで変更し、複数のスレッドからアクセスしているため、読み取りアクセスを含むすべてのアクセスを保護する必要があります。(少なくとも私は. がtype を持っているv.set_a()場合、正当な表現ではないと思います; 私はあなたが意味することを推測しています 、または同様の.)vstd::vector<A>v[i].set_a()

ここでの標準の正確な表現についてはわかりませんが、「ベクトルを変更する」とは、サイズを変更する操作のみを意味し、単一のメンバーを変更する操作ではないと思います。したがってv[0] = x、あるスレッドとv[1]別のスレッドのようなものは、同期なしで合法です。ただし、ベクター内の任意のオブジェクトへのアクセスはすべてベクターへのアクセスであるため、ベクターのサイズが変更された場合、ベクター内のオブジェクトへのすべてのアクセスを保護する必要があります。v[]これには、次のようなものを指定して :によって返される参照を保存したため、「遅延」アクセスが含まれます。

int& ri = v[i];
//  ...
doSomethingWithRi(ri);

いずれかのスレッドがベクトルを変更している場合は、コード ブロック全体を保護する必要があります。

于 2012-07-05T07:26:55.523 に答える