这就是我所拥有的:
由于数据库将经常访问这些节点信息(每秒数千次)并且由于我不经常写,所以我想使用某种双重检查锁定图案。
我知道这里有很多关于双重检查锁定模式的问题,但似乎有很多不同的意见,所以我不知道什么是最适合我的情况。你会对我的设置做什么?
以下是一个例子:
答案 0 :(得分:4)
关于双重检查锁定:
class Foo
{
Resource * resource;
Foo() : resource(nullptr) { }
public:
Resource & GetResource()
{
if(resource == nullptr)
{
scoped_lock lock(mutex);
if(resource == nullptr)
resource = new Resource();
}
return *resource;
}
}
当您检查资源的地址是否为空时,它不是线程安全的。因为在初始化指向它的Resource对象之前,资源指针有可能被分配给非空值。
但是使用C ++ 11的“原子”特性,你可能会有一个双重检查的锁定机制。
class Foo
{
Resource * resource;
std::atomic<bool> isResourceNull;
public:
Foo() : resource(nullptr), isResourceNull(true) { }
Resource & GetResource()
{
if(isResourceNull.load())
{
scoped_lock lock(mutex);
if(isResourceNull.load())
{
resource = new Resoruce();
isResourceNull.store(false);
}
}
return *resource;
}
}
编辑:没有原子
#include <winnt.h>
class Foo
{
volatile Resource * resource;
Foo() : resource(nullptr) { }
public:
Resource & GetResource()
{
if(resource == nullptr)
{
scoped_lock lock(mutex);
if(resource == nullptr)
{
Resource * dummy = new Resource();
MemoryBarrier(); // To keep the code order
resource = dummy; // pointer assignment
}
}
return *const_cast<Resource*>(resource);
}
}
MemoryBarrier()
确保首先创建dummy
,然后将其分配给resource
。
根据{{3}}指针分配在x86和x64系统中将是原子的。 volatile
确保不会缓存resource
的值。
答案 1 :(得分:1)
您是否在询问如何阅读数据库或读取节点线程安全?
如果你正在尝试后者并且你不经常写作,那么为什么不制作你的节点immutable,句号?如果您需要编写内容,请从现有节点复制数据,修改它并创建另一个节点,然后将其放入数据库中。