我有一个地图作为成员变量,多个线程访问地图(读写访问)。现在我必须确保只有一个线程可以访问该地图。但是怎么做呢?什么是最佳解决方案?
我有一个地图作为成员变量,多个线程访问地图(读写访问)。现在我必须确保只有一个线程可以访问该地图。但是怎么做呢?什么是最佳解决方案?
1_48_0
(或其他版本号)替换为 release
。使用 release
将重定向到 Boost 的最新版本。如果每个人都这样做,Google 将不再发布指向过时 Boost 文档的链接。 - Emile Cormier您需要同步访问地图,例如使用POSIX互斥。该链接提供了一些简单易懂的示例,演示如何使用互斥变量。
std::mutex
。这是C++11的一部分,因此并非在所有地方都实现。但gcc-4.6效果还不错。底层实现在Linux中是POSIX线程,在Windows中是Windows线程。实际上,只有一个线程在同一时间访问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;
};
注意迭代器,它们只能在当前线程持有互斥锁的情况下安全操作。
此外,我建议您严格控制地图,将其适应最小的对象,并仅提供您需要的操作。访问地图的方法越少,您错过访问点的可能性就越小。