4

我有一个我想跨多个线程同步的 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 中锁定互斥锁,即使它根本没有修改映射。有没有办法将 my_map 对象本身锁定在函数 A 中,而不是将其锁定在函数 B 中,同时保持线程同步。这样,函数 B 的所有实例/调用都可以继续自由运行,只要函数 A 没有运行?

谢谢

4

3 回答 3

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;
}

从对象本身内部确实没有实际的方法可以做到这一点。

于 2012-06-04T20:04:47.460 回答
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";
    }
}

这意味着每次写入都会获得一个锁,但所有读取都共享一个锁。

于 2012-06-04T19:54:11.823 回答
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";    
}
于 2017-02-24T19:24:55.077 回答