例如,对于操纵容器映射的两个线程,测试迭代器是否仍然有效的正确方法(出于性能原因)是什么?
或者只是间接的方式可以做到这一点。
示例代码:
#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;
}
}
答案 0 :(得分:9)
std::map
根本不是线程安全的。如果一次有多个线程修改同一个映射,那么最终会遇到比失效迭代器更糟糕的问题。我甚至认为你无法保证在被另一个线程修改时你可以从地图中读取任何内容。
STL和线程上的一些页面:
答案 1 :(得分:3)
如果您的STL未提供线程安全std::map
,Intel's TBB offers a thread-safe concurrent_hash_map
(第60和68页)。
抛开线程安全问题,std::map
保证删除不会使被删除的迭代器失效。遗憾的是,没有is_iterator_valid()
方法来验证您持有的迭代器。
有可能实现类似hazard pointers之类的东西,而且TBB也有一些解决问题的方法。
答案 2 :(得分:2)
如果您知道其中一个线程只是读取地图而另一个线程正在操作它,那么最简单的解决方案是让只读线程克隆地图并迭代克隆。
(警告:我知道Java的集合类比我知道的STL要好得多,但这就是我用Java做的。)
答案 3 :(得分:2)
如果您实现了一个读/写解决方案,那么您可以让编写器设置一个标志,使读者的所有迭代器无效。
http://en.wikipedia.org/wiki/Readers-writer_lock
我不会尝试在没有同步的情况下写入地图,正如Josh和Paul Tomblin所说的那样。
答案 4 :(得分:1)
即使您能够判断指针是否有效,它也无法解决您的问题。您正在共享一个没有特权保证的资源。这就是失败的原因。
这个线程序列会失败:
Thread0 ................................线程1
获取iterator-&gt; it0
检查it0是否有效
.............................................获取迭代器 - &GT; IT1
.............................................检查一下it1有效。
擦除(it0)
.............................................擦除( IT1)
您可以添加信号量来访问共享资源。