2011-12-11 86 views
3

我有一个地图作为成员变量和多个访问地图的线程(读写访问)。现在我必须确保只有一个线程可以访问地图。但是我怎么点那个?什么是最好的解决方案?C++ pthread - 如何使地图访问线程安全?

+0

哦,我不知道我可以/不得不接受答案,但我现在做了;) –

回答

1

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

并发读取是可以的,你想避免的是有一个线程修改地图,而其他人正在阅读它。

根据您所需的粒度级别,您可能会考虑使用读写器锁定,这会使多个读取操作并行进行。

具体用法是用升压证明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

Boost包含一些用于共享访问的很好的锁定实现。看看documentation

在你的情况下,你可能需要一个读写锁,因为如果你有很多的读取和很少的写入,互斥锁可能是矫枉过正的。

+0

提升1.36比山丘年龄大,请更新您的链接 –

+0

@Sam Miller,对不起,我正在看一个更老的文件。现在更新。 – Tudor

+0

1.41同样老,我编辑你的问题使用当前版本。 –

3

您需要同步对地图的访问权限,例如使用POSIX mutex。该链接有一些简单的例子可以说明你如何使用互斥变量。

+0

好的,我认为使用POSIX互斥是正确的方法。谢谢! –

1

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