迭代器失效规则是否意味着线程安全?

在这个Stack Overflow答案中,它列出了C ++ 11中标准容器的迭代器失效规则。 特别是有插入

  • [multi]{set,map} :所有迭代器和引用不受影响[23.2.4 / 9]
  • unordered_[multi]{set,map} :所有迭代器在发生重新哈希时都失效,但引用不受影响[23.2.5 / 8]。 如果插入不会导致容器的大小超过z * B ,则不会发生重新散列,其中z是最大加载因子, B是当前桶的数量。 [23.2.5 / 14]

    擦除

  • [multi]{set,map}unordered_[multi]{set,map} :只有迭代器和对擦除元素的引用才会失效

  • 这些规则是否意味着我可以安全地在一个线程中插入和擦除,并安全地在另一个线程访问中查找(使用find )元素,只要这些元素不是在第一个线程中插入和擦除的元素,并确保重新哈哈哈没有发生?

    如果不是,这些规则究竟意味着什么?


    在C ++ std容器上有两种操作。 Reader和Writer操作(这些不是标准使用的术语,但是这更容易)。 另外,对容器中的元素进行操作。

    const方法是一个阅读器的方法,因为是“查找”功能,这些功能只非const ,因为它们返回非const参考的元件(或类似的)。 标准中有一个完整的列表,但常识应该起作用。 vector::operator[]begin()map::find()都是“读者”。 map::operator[] 不是 “Reader”。

    您可以有任何数量的线程在同一时间参与阅读器操作没有问题。

    如果您有任何线程参与Writer操作,则容器上不会出现其他访问

    无法同时安全地安装一台Reader和一台Writer。 如果你有任何作家,你必须排除所有其他访问。

    您可以一次安全地拥有1337个阅读器。

    对元素的操作有些类似,除了写入元素只需要排除对该元素的其他访问权限。 你有责任让你的const方法相互发挥很好。 ( std保证容器的const方法只会调用元素的const方法)

    请注意,更改std:: associative容器中的排序顺序是UB,而无需修改容器。

    一个没有失效的迭代器,你只需要对元素进行操作,我相信它会作为元素的操作。 只需要在该元素上进行同步。

    请注意, std::vector<bool>不遵循上述规则。


    如果违反上述规则,C ++ std库不会阻止你。 它只是说明存在竞争条件 - 也就是未定义的行为。 任何事情都可能发生。 在C ++ std库中,如果你不需要什么东西,你不需要支付它:而单线程使用这些容器不需要同步的重量。 所以你不会默认它。

    std::shared_timed_mutex或者std::experimental::shared_mutex都可以用来保证上面的结果。 用于写入的unique_lock和用于读取的shared_lock 。 写访问的元素必须是shared_lock把守的容器上编辑,并以某种方式防护,以防无死锁重叠访问相同的元件。


    迭代器失效规则与线程安全规则相对正交。


    事实上,容器元素的迭代器不会失效,绝不意味着容器本身的线程安全。 例如,size成员变量需要自动修改,这与迭代器在插入/删除时被无效(或不)的问题完全不同。

    TL;博士; 没有。

    这些规则只是简单地告诉你一个元素的迭代器是否被操作无效。 例如,当一个矢量调整大小时,底层数组在其他地方被重新分配,所以如果你有一个元素的迭代器(或指针),它在调整大小后将不再有效(因为它会指向旧数组的已删除元素)。


    使用find意味着遍历,至少在元素的一个子集上。 在[multi]{set,map}inserterase导致重新平衡底层树,这会影响节点之间的链接。 如果重新平衡发生在同一时间find ,坏事会发生。

    同样,如果您在unordered_[multi]{set,map} inserterase期间尝试find ,则会发生不好的事情。 insert可能导致重新哈希。 inserterase需要链接/取消链接列表中的元素。 如果某个find在链接/取消链接期间在列表中搜索,则会丢失。

    [] on [unordered][multi]{set,map}是“找到并插入,如果找不到”的简写。 atfind简写。 所以不,这些也不安全。

    如果您有一个现有的迭代器到[multi]{set,map} ,则可以继续取消引用(但不递增/递减)该迭代器,而插入或删除另一个元素。 对于unordered_[multi]{set,map} ,只有在可以保证在插入操作下不会发生重新刷新的情况下(它在擦除过程中从不发生),这才是真实的。

    链接地址: http://www.djcxy.com/p/73329.html

    上一篇: Do the iterator invalidation rules mean thread safety?

    下一篇: Why does this vector iterator not become invalidated?