在锁内的STL容器上执行耗时的操作

时间:2011-01-11 05:30:17

标签: c++ multithreading

我有一个unordered_map的unordered_map,它存储一个对象的指针。无序映射由多个线程共享。我需要遍历每个对象并执行一些耗时的操作(比如通过网络等发送)。我怎么能锁定多个unordered_map以便它不会被阻塞太长时间?

typedef std::unordered_map<string, classA*>MAP1;
typedef std::unordered_map<int, MAP1*>MAP2;
MAP2 map2;
pthread_mutex_lock(&mutexA) //how could I lock the maps? Could I reduce the lock granularity?
for(MAP2::iterator it2 = map2.begin; it2 != map2.end; it2++)
{
  for(MAP1::iterator it1 = *(it2->second).begin(); it1 != *(it2->second).end(); it1++)
  {
    //perform some time consuming operation on it1->second eg
    sendToNetwork(*(it1->second));
  }
}
pthread_mutex_unlock(&mutexA)

3 个答案:

答案 0 :(得分:0)

您可以将所有这些对象存储在List之类的其他结构中并进行迭代,这样您就不必锁定地图。

您还可以尝试创建数据副本并处理副本 - 这样就可以在处理副本时修改地图。

答案 1 :(得分:0)

在dr dobbs上查看专门针对您问题的article by herb sutter

一般的想法是在封装资源的对象内部有一个线程。线程接受对资源执行操作的请求,允许调用者推送请求然后继续,让内部线程执行请求。

另外,建议您直接使用boost.thread代替pthread,这样做会少得多痛苦。

答案 2 :(得分:0)

通常长时间持有互斥锁并不是一个好习惯。这里已经提到过的一种常见方法是拥有一个对象队列,它将读取和处理工作线程中的对象。

在你的例子中,mutexA在你迭代它时保护map2不被修改,你可以这样做:

std::vector<MAP1*> map1Queue;
pthread_mutex_lock(&mutexA);
for(MAP2::iterator it2 = map2.begin; it2 != map2.end; ++it2) {
  map1Queue.push_back(it2->second);
}
pthread_mutex_unlock(&mutexA);
// Now you can process objects from map1Queue in worker thread

唯一的问题是你需要保证MAP1 *仍然有效,可能使用boost :: shared_ptr而不是raw_pointers。