繁体   English   中英

从std :: deque线程对emplace_back()和operator []()的并发调用是否安全?

[英]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修饰符

(......)

  1. 效果:在双端队列中间的插入使所有迭代器和对双端队列元素的引用无效。 在deque两端的插入使deque的所有迭代器无效,但对deque元素的引用的有效性没有影响。

(......)

同时在标准类的对象上调用任意两个方法是不安全的,除非两者都是const ,或者除非另有说明(例如std::mutex::lock() )。 这在更详细的探讨这里

因此,同时使用emplace_backoperator[] 并不安全。 但是,由于您引用的引用/指针有效性规则,您可以安全地使用以前获得的对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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM