0

可能重复:
STL 向量和线程安全

一个简单的例子:

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

假设,v在线程 1 和线程 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)对此非常清楚。您正在一个线程中修改一个对象(向量),并从多个线程访问它,因此所有访问(包括读取访问)都必须受到保护。(至少我想。 v.set_a()不是合法表达 if vhas type std::vector<A>;我猜你的意思是 v[i].set_a(),或类似的东西。)

我不确定此处标准的确切措辞,但我认为“修改向量”仅意味着更改其大小的操作,而不是修改单个成员的操作。v[0] = x因此,一个线程和另一个线程中的事情在v[1]没有同步的情况下是合法的。但是所有对向量中任何对象的访问,都是对向量的访问,所以如果向量的大小发生变化,所有对向量中对象的访问都必须受到保护。这包括“延迟”访问,因为您已经保存了由v[]: 返回的引用,例如:

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

如果任何线程正在修改向量,则必须保护整个代码块。

于 2012-07-05T07:26:55.523 回答