c++ pthread - 如何使map访问线程安全?

3

我有一个地图作为成员变量,多个线程访问地图(读写访问)。现在我必须确保只有一个线程可以访问该地图。但是怎么做呢?什么是最佳解决方案?


哦,我不知道我可以/必须接受答案,但现在我已经这样做了 ;) - Tobi Weißhaar
4个回答

4
Boost中包含一些用于共享访问的良好锁实现。请查看文档。在您的情况下,如果有大量读取和很少写入,则可能需要读写锁,因为互斥锁可能过于严格。请参考此处的文档。

@Sam Miller,抱歉,我看的是旧文档。现在已经更新了。 - Tudor
1.41和现在的版本一样旧,我编辑了你的问题以使用当前版本。 - Sam Miller
1
在发布指向 Boost 文档的链接时,最好将 URL 中的 1_48_0(或其他版本号)替换为 release。使用 release 将重定向到 Boost 的最新版本。如果每个人都这样做,Google 将不再发布指向过时 Boost 文档的链接。 - Emile Cormier

3

您需要同步访问地图,例如使用POSIX互斥。该链接提供了一些简单易懂的示例,演示如何使用互斥变量。


好的,我认为使用POSIX互斥锁是正确的方法。谢谢! - Tobi Weißhaar

1
如果您有最新的编译器,可以使用基于boost实现的std::mutex。这是C++11的一部分,因此并非在所有地方都实现。但gcc-4.6效果还不错。底层实现在Linux中是POSIX线程,在Windows中是Windows线程。

1

实际上,只有一个线程在同一时间访问map的前提是略微偏离的。

并发读取是可以的,你要避免的是当其他线程正在读取时,有一个线程修改了map。

根据你需要的粒度级别,你可以考虑使用读/写锁,这将允许多个读操作并行进行。

具体用法可以参考这里,使用Boost进行演示:

boost::shared_mutex _access;
void reader()
{
  // get shared access
  boost::shared_lock<boost::shared_mutex> lock(_access);

  // now we have shared access
}

void writer()
{
  // get upgradable access
  boost::upgrade_lock<boost::shared_mutex> lock(_access);

  // get exclusive access
  boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
  // now we have exclusive access
}

接下来,只需要方便地包装地图访问即可。例如,您可以使用通用代理结构:

template <typename Item, typename Mutex>
class ReaderProxy {
public:
  ReaderProxy(Item& i, Mutex& m): lock(m), item(i) {}

  Item* operator->() { return &item; }

private:
  boost::shared_lock<Mutex> lock;
  Item& item;
};

template <typename Item, typename Mutex>
class WriterProxy {
public:
  WriterProxy(Item& i, Mutex& m): uplock(m), lock(uplock), item(i) {}

  Item* operator->() { return &item; }

private:
  boost::upgrade_lock<Mutex> uplock;
  boost::upgrade_to_unique_lock<Mutex> lock;
  Item& item;
};

而且你可以像这样使用它们:

class Foo {
  typedef ReaderProxy< std::map<int, int>, boost::shared_mutex> Reader;
  typedef WriterProxy< std::map<int, int>, boost::shared_mutex> Writer;

public:
  int get(int k) const {
    Reader r(map, m);

    auto it = r->find(k);
    if (it == r->end()) { return -1; }
    return it->second;
  }

  void set(int k, int v) {
    Writer w(map, m);

    w->insert(std::make_pair(k, v));
  }
private:
  boost::shared_mutex m;
  std::map<int, int> map;
};

注意迭代器,它们只能在当前线程持有互斥锁的情况下安全操作。

此外,我建议您严格控制地图,将其适应最小的对象,并仅提供您需要的操作。访问地图的方法越少,您错过访问点的可能性就越小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接