2

我想转储 unordered_map 的键,同时能够同时添加和擦除元素。完全转储需要 4 秒,太长了。是否可以在单独的线程中转储,如下所示:

while (1) {
    pthread_mutex_lock( &mutex ); 
    if(iter!=map.end()){
        x=iter->first
        iter++;    
    }
    pthread_mutex_unlock( &mutex );

    do_this(x);  // this takes time to complete
}

在主线程中我有:

pthread_mutex_lock( &mutex ); 
map.erase(iter);

unordered map 的擦除方法是否有问题,因为擦除后迭代器将无效。

还有其他安全的并行转储方式吗?

4

3 回答 3

3

对于unordered_map(以及一般的关联容器),erase()成员函数不会使迭代器和对除已删除元素之外的其他元素的引用无效。

但是,在这里您可能正在擦除一个元素并使其迭代器无效,而您的循环持有该元素的迭代器:例如,如果您碰巧擦除了将在循环中取消引用的下一个迭代器所引用的元素。

因此,您需要注意要在循环的下一个循环中处理的迭代器没有引用您要删除的元素while

pthread_mutex_lock( &mutex ); 
if (i != iter)
{
    map.erase(i);
}
else
{
    // Maybe store in a queue of elements to be removed after the loop is done
}

iter循环中使用的迭代器变量在哪里。

于 2013-02-03T14:37:17.093 回答
1

请参阅:如果在从头到尾迭代时在地图元素上调用 erase() 会发生什么?

do_this由于在调用调用它的方法之前增加迭代器erase不会造成任何麻烦。

只是一个想法:使用您当前的算法,我认为您根本不需要互斥锁。

于 2013-02-03T14:39:59.283 回答
1

您可以通过迭代桶而不是迭代元素来获得一些(但不是全部 - 这实际上只是允许您交错操作,以便擦除不必等待整个 4 秒)所需的并行性。只要桶数不减少,这将是安全的

IE

pthread_mutex_lock( &mutex ); 
size_t count = map.bucket_count();
pthread_mutex_unlock( &mutex );

for(size_t i = 0; i<count; ++i){
  pthread_mutex_lock( &mutex );
  for(auto it = map.begin(i); it != map.end(i); ++i)
    do_this(it->first);
  pthread_mutex_unlock( &mutex );
}

如果您想将 do_this 从互斥锁中拉出,则需要在其他结构中累积值

另一个建议,具体取决于该映射在其他地方的使用方式,您可以将元素交换为某个已知的无效值而不是擦除,然后让执行转储/do_this 的线程在看到该值时执行实际擦除.

于 2013-02-03T14:46:08.173 回答