3

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

#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;
    }
}
4

5 回答 5

9

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

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

于 2009-01-12T16:39:36.370 回答
3

如果您的 STL 不提供线程安全std::map英特尔的 TBB 提供线程安全concurrent_hash_map(第 60 和 68 页)。

将线程安全问题放在一边,std::map 确实保证删​​除不会使迭代器无效,而不是被删除的迭代器。不幸的是,没有一种is_iterator_valid()方法可以验证您持有的迭代器。

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

于 2009-01-12T18:53:35.447 回答
2

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

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

于 2009-01-12T16:39:57.743 回答
2

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

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

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

于 2009-01-12T16:46:19.120 回答
1

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

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

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

获取迭代器->it0

检查 it0 是否有效

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

................................................检查 it1 是否有效.

擦除 (it0)

.............................擦除 (it1)

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

于 2009-04-17T15:17:40.550 回答