我有一个地图作为成员变量和多个访问地图的线程(读写访问)。现在我必须确保只有一个线程可以访问地图。但是我该怎么做呢?对此有什么最好的解决方案?
答案 0 :(得分:4)
Boost包含一些用于共享访问的很好的锁实现。看看documentation。
在你的情况下,你可能需要一个读写锁,因为如果你有大量的读取和很少的写入,互斥锁可能是过度的。
答案 1 :(得分:3)
您需要同步对地图的访问权限,例如使用POSIX mutex。该链接有一些简单的例子,说明如何使用互斥变量。
答案 2 :(得分:1)
实际上,在给定时间只有一个线程应该访问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;
};
请注意迭代器,只有在当前线程保持互斥锁时才能安全地操作它们。
此外,我建议您严格控制地图,将其放入有意义的最小对象中,并仅提供您需要的操作。最少的方法可以访问地图,错过一个接入点的可能性就越小。
答案 3 :(得分:1)
如果您有最新的编译器,则可以使用std::mutex
(基于boost实现)。这是C ++ 11的一部分,所以它并没有在任何地方实现。 gcc-4.6的效果相当不错。
底层实现是Linux中的POSIX线程和Windows中的Windows线程。