【问题标题】:c++ pthread - How to make map access threadsafe?c++ pthread - 如何使地图访问线程安全?
【发布时间】:2011-12-11 13:53:55
【问题描述】:

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

【问题讨论】:

  • 哦,我不知道我可以/必须接受答案,但我现在做到了;)

标签: c++ multithreading hashmap


【解决方案1】:

Boost 包含一些不错的共享访问锁实现。看看documentation

在您的情况下,您可能需要一个读写锁,因为如果您有大量读取和很少写入,则互斥锁可能会过度使用。

【讨论】:

  • @Sam Miller,抱歉,我正在查看较旧的文档。现已更新。
  • 1.41 一样旧,我编辑了您的问题以使用当前版本。
  • 在发布指向 Boost 文档的链接时,最好将 URL 中的 1_48_0(或其他)替换为 release。使用 release 将重定向到最新版本的 Boost。如果每个人都这样做,Google 将停止发布指向过时 Boost 文档的链接。
【解决方案2】:

您需要同步对地图的访问,例如使用POSIX mutex。该链接有一些简单易懂的示例,说明如何使用互斥变量。

【讨论】:

  • 好的,我认为使用 POSIX 互斥锁是正确的方法。谢谢!
【解决方案3】:

实际上,在给定时间只有单个线程应该访问map 的前提有点不妥。

并发读取是可以的,您要避免的是在其他人正在读取地图时让线程修改地图。

根据您需要的粒度级别,您可能会考虑使用读取器/写入器锁,它可以让多个读取并行进行。

使用 Boost 演示了 here 的确切用法:

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

但请注意迭代器,它们只能在互斥锁被当前线程持有时安全地操作。

另外,我建议您严格控制地图,将其放入有意义的最小对象中,并仅提供您需要的那些操作。访问地图的方法越少,您错过一个访问点的可能性就越小。

【讨论】:

    【解决方案4】:

    如果你有一个最近的编译器,你可以使用std::mutex(它基于 boost 实现)。这是 C++11 的一部分,因此并未在任何地方实现。 gcc-4.6 工作得相当好。 底层实现是 linux 中的 POSIX 线程和 Windows 中的 Windows 线程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-23
      • 1970-01-01
      • 2015-09-17
      • 2018-04-27
      • 2019-11-23
      相关资源
      最近更新 更多