【问题标题】:Is there any way to check if an iterator is valid?有什么方法可以检查迭代器是否有效?
【发布时间】:2010-09-30 23:07:54
【问题描述】:

例如,对于操作容器映射的两个线程,测试迭代器是否仍然有效(出于性能原因)的正确方法是什么?
或者只能通过间接的方式来做到这一点。 示例代码:

#define _SECURE_SCL 1
//http://msdn2.microsoft.com/en-us/library/aa985973.aspx
#define _SECURE_SCL_THROWS 1

#include "map"
#include "string"
#include "exception"
#include "iostream"

using namespace std;

void main(void)
{
    map<string, string> map_test;
    map<string, string>::iterator iter_map_test;

    map_test [ "AAAAA" ] = "11111";
    map_test [ "BBBBB" ] = "22222";
    map_test [ "CCCCC" ] = "33333";

    iter_map_test = map_test.find ("BBBBB");

    map_test.erase ("BBBBB");

    try
    {
        string value = (*iter_map_test).second;
    }
    catch ( exception & e )
    {
            cout << e.what() << endl;
    }
    catch ( ... )
    {
            cout << "generic exception." << endl;
    }
}

【问题讨论】:

标签: c++ performance stl iterator


【解决方案1】:

std::maps 根本不是线程安全的。如果您一次有多个线程修改同一个映射,您最终会遇到比无效迭代器更糟糕的问题。我什至不认为您可以保证您可以在地图被另一个线程修改时从地图中读取任何内容。

关于 STL 和线程的一些页面:

【讨论】:

  • 该标准根本不保证线程安全,但个别实现可能会提供更强的保证。因此,请检查文档以查看您使用的实现是否是线程安全的。
【解决方案2】:

如果您知道其中一个线程只会读取地图,而另一个线程可能正在操作它,最简单的解决方案是让只读线程克隆地图并遍历克隆。

(警告:我比 STL 更了解 Java 的集合类,但这是我在 Java 中的做法。)

【讨论】:

    【解决方案3】:

    如果您实现了读取器/写入器解决方案,那么您可以让写入器设置一个标志,使读取器的所有迭代器无效。

    http://en.wikipedia.org/wiki/Readers-writer_lock

    正如 Josh 和 Paul Tomblin 所说,我不会尝试在不同步的情况下写入地图。

    【讨论】:

      【解决方案4】:

      如果您的 STL 不提供线程安全的 std::mapIntel's TBB offers a thread-safe concurrent_hash_map(第 60 和 68 页)。

      抛开线程安全问题不谈,std::map确实保证删除不会使除被删除的迭代器之外的迭代器失效。不幸的是,没有 is_iterator_valid() 方法来验证您持有的迭代器。

      也许可以实现hazard pointers 之类的东西,TBB 也有一些解决该问题的方法。

      【讨论】:

        【解决方案5】:

        即使您能够判断指针是否有效,它也无法解决您的问题。您正在共享一个没有排他性保证的资源。这就是失败的原因。

        在这个线程序列中会失败:

        线程0.......................线程1

        获取迭代器->it0

        检查it0是否有效

        ..................................获取迭代器->it1

        ..................................检查it1 有效。

        擦除 (it0)

        ..................................删除(它1)

        您可以添加信号量来访问共享资源。

        【讨论】:

        • 细节就是这样!如果一个线程擦除 it0,如何检测 it1 不再有效。
        • 这就是整个问题,在 it1 检查迭代器时它是有效的,所以仅仅检查有效性是行不通的。在修改资源时,您必须使用信号量来锁定资源。
        • 锁定资源访问并不能保证任何事情,您必须使用一个标志来指示应该丢弃迭代器。是我必须实施的吗?
        • 这就是信号量的用途。如果你锁定了一个资源,另一个线程必须等到该资源空闲后才请求迭代器,并且它总是有效的。
        猜你喜欢
        • 2011-01-04
        • 2017-02-23
        • 1970-01-01
        • 2011-01-17
        • 1970-01-01
        • 2013-01-18
        • 1970-01-01
        • 2015-08-19
        • 2018-01-31
        相关资源
        最近更新 更多