一个简单的非锁定读取并发映射的算法?

时间:2014-07-09 18:19:12

标签: c++ multithreading map concurrency

我正在尝试编写一个线程安全的映射,但从不锁定或阻塞读取。我的尝试是使用在写入时复制出来的只读映射。想法是 get()是无锁的, put()将当前的只读底层映射复制到新映射,执行put,并交换掉新的当前底层地图。 (是的, put()是低效的,因为它复制整个地图,但我不关心我的用例)

我第一次尝试使用std :: atomic< * StringMap>对于只读地图 BUT ,这有一个很大的错误,可能是由于我的java背景。 get()原子地获取一个指向底层地图的指针,当它加载它时可能是也可能不是当前的地图(这没关系)。但是 put()在将基础地图换成新地图之后删除它。如果 get()正在调用旧地图,就像它被删除一样,这显然会崩溃。

我的一位朋友建议 shared_ptr ,但他不确定shared_ptr操作是否在封面下进行任何锁定。 文档说这是线程安全的。 编辑:正如nosid指出的那样,它不是线程安全的,我需要std :: atomic的特殊原子操作。

所以我的问题是:1。这个算法是否可行? 2. shared_ptr操作是否进行任何锁定,尤其是在访问时?

#include <unordered_map>
#include <atomic>
#include <pthread.h>
#include <memory>

typedef std::unordered_map<std::string, std::string> StringMap;

class NonBlockingReadMap {
private:
    pthread_mutex_t fMutex;    
    std::shared_ptr<StringMap> fspReadMapReference;


public:

    NonBlockingReadMap() {
        fspReadMapReference = std::make_shared<StringMap>();
    }

    ~NonBlockingReadMap() {
        //so, nothing here?
    }

    std::string get(std::string &key) {
        //does this access trigger any locking?
        return fspReadMapReference->at(key);
    }

    void put(std::string &key, std::string &value) {
        pthread_mutex_lock(&fMutex);
        std::shared_ptr<StringMap> spMapCopy = std::make_shared<StringMap>(*fspReadMapReference);
        std::pair<std::string, std::string> kvPair(key, value);
        spMapCopy->insert(kvPair);
        fspReadMapReference.swap(spMapCopy);
        pthread_mutex_unlock(&fMutex);
    }

    void clear() {
        pthread_mutex_lock(&fMutex);
        std::shared_ptr<StringMap> spMapCopy = std::make_shared<StringMap>(*fspReadMapReference);
        fspReadMapReference.swap(spMapCopy);
        spMapCopy->clear();
        pthread_mutex_unlock(&fMutex);
    }

};

2 个答案:

答案 0 :(得分:2)

您的代码在std::shared_ptr上包含数据竞争,并且在C ++中未定义具有数据竞争的程序的行为。

问题是:类std::shared_ptr不是线程安全的。但是,std::shared_ptr有一些特殊的原子操作,可用于解决问题。

您可以在以下网页上找到有关这些原子操作的更多信息:

答案 1 :(得分:1)

Reader应该做两个操作:get和put。 get总是检索新指针并增加原子计数。释放指针并减少。当计数变为零时删除地图。 作者创建了一个新的地图,然后开始了。然后它会对旧地图进行标记以将其标记为删除。

相关问题