一个简单的例子:
struct A {
int a;
void set_a (int x)
{
... // line-1
... // line-2
this->a = x; // line-3
}
};
...
vector<A> v; // somewhere
假设,v
在thread-1和thread-2中共享。始终在线程1中调用v.set_a()
,在线程2中调用v.push_back()
。所以没有线程安全问题。
以下事件序列会发生什么:
v.set_a()
push_back()
,
resize()
,...)v
必须
搬到其他地方会导致未定义的行为吗?如果是,那么对于这种情况,最优雅的解决方案是什么?
答案 0 :(得分:3)
没有什么可以说矢量大小调整是线程安全的,所以必须假设它不是。在你的例子中,我肯定会遇到问题,因为你依赖于许多非原子操作。一个优雅的解决方案是简单地将其包装在一个线程安全的版本中。
答案 1 :(得分:2)
标准(C ++ 11,以前的Posix)对此非常清楚。
您正在一个线程中修改一个对象(向量)并访问它
来自更多的一个线程,所以所有访问,包括读取访问,
必须得到保护。 (至少我猜想。v.set_a()
不合法
表达式v
的类型为std::vector<A>
;我猜你的意思是
v[i].set_a()
,或类似的东西。)
我不确定这里标准的确切措辞,但是我
会假设“修改矢量”仅表示操作
更改其大小,而不是修改单个成员的操作。所以
一个线程中的v[0] = x
和另一个线程中的v[1]
之类的内容是合法的
没有同步。但是对向量中任何对象的所有访问,
是访问向量,所以如果有大小的变化
向量,必须保护对向量中对象的所有访问。这个
包括“延迟”访问,因为您已保存返回的引用
通过v[]
:给出类似的内容:
int& ri = v[i];
// ...
doSomethingWithRi(ri);
如果任何线程正在修改,则必须保护整个代码块 矢量。