我试图编写一个线程安全的映射表,但在读取时不会发生锁定或阻塞。我的尝试是使用只读映射表,在写入时将其复制出来。思路是get()是无锁的,而put()将当前只读基础映射表复制到一个新的映射表中,执行put操作,并将当前基础映射表与新映射表交换(是的,put()效率低下,因为它复制了整个映射表,但我对我的用例不关心)。
我第一次尝试使用std::atomic<*StringMap>作为只读映射表,但是存在一个巨大的错误,可能是由于我的Java背景。 get()以原子方式获取指向基础映射表的指针,加载它时可能是当前映射表也可能不是(这没问题)。但是put()在将其与新映射表交换后删除基础映射表。如果get()在刚好删除旧映射表时调用旧映射表,那么这显然会崩溃。
我的一个朋友建议使用shared_ptr,但他不确定共享指针操作在内部是否执行任何锁定。尽管文档说它是线程安全的,但也有可能不是。所以我的问题是: 1. 这个算法可行吗?2.共享指针操作是否会进行任何锁定,特别是在访问时?
我第一次尝试使用std::atomic<*StringMap>作为只读映射表,但是存在一个巨大的错误,可能是由于我的Java背景。 get()以原子方式获取指向基础映射表的指针,加载它时可能是当前映射表也可能不是(这没问题)。但是put()在将其与新映射表交换后删除基础映射表。如果get()在刚好删除旧映射表时调用旧映射表,那么这显然会崩溃。
我的一个朋友建议使用shared_ptr,但他不确定共享指针操作在内部是否执行任何锁定。尽管文档说它是线程安全的,但也有可能不是。所以我的问题是: 1. 这个算法可行吗?2.共享指针操作是否会进行任何锁定,特别是在访问时?
#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);
}
};