在C ++中,有没有办法锁定对象本身?

时间:2012-06-04 18:20:02

标签: c++ multithreading synchronization mutex

我有一个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的所有实例/调用都会继续自由运行吗?

由于

3 个答案:

答案 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_mutexstd::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";    
}