我有一个stl地图,我希望在几个线程之间进行同步。目前我有......
功能A(修改地图)
void Modify(std::string value)
{
pthread_mutex_lock(&map_mutex);
my_map[value] = value;
pthread_mutex_unlock(&map_mutex);
}
功能B(读取地图)
std::string Read(std::string key)
{
std::string value;
pthread_mutex_lock(&map_mutex);
std::map<std::string, std::string>::iterator it = my_map.find(key);
pthread_mutex_unlock(&map_mutex);
if(it != my_map.end())
{
return it->second;
}
else
{
return "DNE";
}
}
由于互斥锁,这会在所有线程之间同步。但是,我必须在函数B中锁定互斥锁,即使它根本没有修改映射。有没有办法在函数A中锁定my_map对象本身,而不是在保持线程同步的同时将其锁定在函数B中。这样,只要函数A没有运行,函数B的所有实例/调用都会继续自由运行吗?
由于
答案 0 :(得分:3)
您不仅要锁定容器,还要锁定对容器的访问,即任何迭代器或指向它的指针。您需要将这些访问移动到代码的锁定区域。
std::string Read(std::string key)
{
std::string value = "DNE";
pthread_mutex_lock(&map_mutex);
std::map<std::string, std::string>::iterator it = my_map.find(key);
if(it != my_map.end())
{
value = it->second;
}
pthread_mutex_unlock(&map_mutex);
return value;
}
在对象本身内部实际上没有实际的方法。
答案 1 :(得分:1)
警告:我没有编译或测试任何此类内容,但我过去也做过类似的事情。
第一步是用类控制互斥锁,如下:
class Lock {
public:
Lock(Mutex& mutex) {
pthread_mutex_lock(mutex);
}
~Lock(Mutex& mutex) {
pthread_mutex_unlock(mutex);
}
};
这样可以避免各种问题,例如,如果您的地图引发异常。
然后您的修改变为:
void Modify(std::string value)
{
Lock(map_mutex);
my_map[value] = value;
}
创建引用计数锁类:
class RefCntLock {
private:
static int count;
static Lock* lock;
public:
RefCountLock(Mutex& mutex) {
// probably want to check that the mutex matches prior instances.
if( !lock ) {
lock = new Lock(mutex);
count++;
}
}
~RefCountLock() {
--count;
if( count == 0 ) {
delete lock;
lock = NULL;
}
}
};
(注意:很容易将其概括为处理多个互斥锁。)
在read
中,使用RefCntLock类:
std::string Read(std::string key)
{
{
RefCntLock(&map_mutex);
std::map<std::string, std::string>::iterator it = my_map.find(key);
}
if(it != my_map.end())
{
return it->second;
}
else
{
return "DNE";
}
}
这意味着每次写入都会获得锁定,但所有读取都会共享锁定。
答案 2 :(得分:0)
在即将推出的C ++ 17标准中,您可以使用std::shared_mutex
和std::shared_lock
来允许多个读者进行独占读取访问,并使用std::unique_lock
来实现独占写访问权。
std::shared_mutex map_lock;
void Modify(std::string value)
{
auto write_lock = std::unique_lock(map_lock);
my_map[value] = value;
}
std::string Read(std::string key)
{
auto read_lock = std::shared_lock(map_lock);
auto it = my_map.find(key);
return (it != my_map.end()) ? it->second : "DNE";
}