[英]Exception in std::vector<>::emplace_back() safe?
[英]Are concurrent calls to emplace_back() and operator[]() from std::deque thread safe?
emplace_back()
文档的摘录:
- 迭代器有效性
与此容器相关的所有迭代器都是无效的,但指针和引用仍然有效,指的是它们在调用之前引用的相同元素。
- 数据竞赛
容器已修改。
调用不访问任何包含的元素:同时访问或修改它们是安全的(尽管请参见上面的迭代器有效性 )。
以及来自operator[]()
的文档摘录:
- 数据竞赛
访问容器(const和非const版本都不会修改容器)。
可能会访问或修改元素n 。 同时访问或修改其他元素是安全的。
因此,鉴于deque的某个实例至少有一个元素,通过operator[]()
访问它并在容器上同时调用emplace_back()
确实是线程安全的吗?
我倾向于说它是,但无法决定emplace_back()
的文档中的“访问”是否包含使用operator[]()
如:
int access( std::deque< int > & q )
{
return q[ 0 ];
}
void emplace( std::deque< int > & q , int i )
{
q.emplace_back( i );
}
其中两个函数同时调用,或者“访问”仅适用于已经采用某些引用或指针的元素:
std::deque< int > q { 1 };
auto * ptr = & q[ 0 ]
std::thread t1 ( [ ptr ]{ * ref = 0; } );
std::thread t2 ( [ & q ]{ q.emplace_back( 2 ); } );
编辑 :为了进一步参考,这里是C ++ 14标准(实际上, 2014年11月的工作草案,N4296 )关于引用和迭代器有效性的deque
插入的说明:
- 23.3.3.4 deque修饰符
(......)
- 效果:在双端队列中间的插入使所有迭代器和对双端队列元素的引用无效。 在deque两端的插入使deque的所有迭代器无效,但对deque元素的引用的有效性没有影响。
(......)
同时在标准类的对象上调用任意两个方法是不安全的,除非两者都是const
,或者除非另有说明(例如std::mutex::lock()
)。 这在更详细的探讨这里
因此,同时使用emplace_back
和operator[]
并不安全。 但是,由于您引用的引用/指针有效性规则,您可以安全地使用以前获得的对deque
元素的引用以及对emplace_back
/ push_back
的调用,例如:
int main()
{
std::deque<int> d;
d.push_back(5);
auto &first = d[0];
auto task = std::async(std::launch::async, [&] { first=3; });
d.push_back(7);
task.wait();
for ( auto i : d )
std::cout << i << '\n';
}
这将安全地输出3和7.请注意, first
在启动异步任务之前创建引用。
编辑注释:这个答案的结论是错误的,即[]
和emplace_back
可以安全地同时使用。 Arne的回答是正确的。 由于评论有用,请将此留在这里而不是删除。
编辑2:嗯,从技术上讲,我没有得出那个结论,但它有点暗示。 Arne是更好的答案。
虽然我并不完全信任源,但是这篇文档似乎在说什么,只要不通过迭代器执行它,并发访问其他值是线程安全的。
这种情况的原因是emplace_back
不会以任何方式触及其他值。 如果容量太低而无法添加其他元素,则会分配新页面。 这不会影响其他元素。 因此通过其他线程使用这些值是安全的。 它不会导致数据竞争,因为没有访问/修改相同的数据。
对于这种情况,容器不需要以任何方式是线程安全的。 这就像在修改a[1]
时访问a[0]
一样。 只要您正确访问/修改数据(不会导致UB),这是一个安全的操作。 您不需要任何锁保护,因为您没有同时使用相同的数据。
我更关心的是size
。 这很可能将是在一个值deque
由修改emplace
,并通过读取size
。 如果没有保护,这将导致数据竞争。 文档没有说明这一点,只涉及元素的访问,当然可以同时调用size
。
根据这个答案 ,除上述情况外,标准容器对螺纹安全性没有任何保证。 换句话说,您可以同时访问/修改不同的元素,但其他任何内容都可能导致数据竞争。 换句话说,标准容器不是线程安全的,不提供任何并发保护。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.