【发布时间】:2016-05-18 10:40:02
【问题描述】:
上下文
我有一个类(比方说Foo)管理一些集中式资源作为静态地图中的历史记录,具有读取它们的访问器和添加新数据的功能(无法删除密钥):
class Foo
{
private:
static std::map<std::string,MyDataStructure> data;
public:
static const MyDataStructure& getData(const std::string& key)
{
assert(Foo::data.count(key) > 0); // Must exist
return Foo::data[key];
}
static void addData(const std::string& key, const MyDataStructure& d)
{
assert(Foo::data.count(key) == 0); // Can not already exist
Foo::data[key] = d;
}
};
为了避免并发问题,我添加了一个我这样管理的互斥锁:
class Foo
{
private:
static std::map<std::string,MyDataStructure> data;
static boost::mutex mutex_data;
public:
static const MyDataStructure& getData(const std::string& key)
{
boost::mutex::scoped_lock lock(Foo::mutex_data);
assert(Foo::data.count(key) > 0); // Must exist
return Foo::data[key];
}
static void addData(const std::string& key, const MyDataStructure& d)
{
boost::mutex::scoped_lock lock(Foo::mutex_data);
assert(Foo::data.count(key) == 0); // Can not already exist
Foo::data[key] = d;
}
};
我的问题
- 我的第一个问题是关于
getData返回的对Foo::data的引用:这个引用超出了互斥锁的范围,那么它可能有问题吗?是否有可能由于另一个访问添加数据而丢失引用?简而言之:地图中的引用总是相同的吗? - 如果是,
assert是否需要在addData中?如果我更改链接到地图中现有键的数据,参考可以更改吗? -
getData中是否需要锁?如果std::map已经是多线程安全的,我想可能不会。
【问题讨论】:
-
您是在此处使用断言,因为您的程序逻辑不允许在添加数据之前调用
getData,还是使用它来检查地图中是否存在数据? -
@MohamadElghawi :这并不是真的不允许,但显然不是使用该对象的好方法。在我的程序中,
Foo::data是关于创建具有 uniqid 的对象的历史。尝试访问不存在的对象的历史是没有意义的。我使用assert,因为如果在发布模式下创建并返回空历史记录,这不是什么大问题。 -
如果不被禁止,那么我建议使用断言以外的东西。断言通常不会编译到发布版本中,因此您的检查不会停止存在于生产环境中。
-
这正是我所说的:在发布模式下不需要。对于使用该对象的开发人员来说,这是一个错误,而不是对于应用程序的用户。 (参见按合同设计的编程)
-
其实我也有一个
static bool hasKey(const std::string& key)函数,供用户在调用之前检查key是否存在。用户有责任仅使用现有密钥调用 getData,并且他拥有执行此操作的工具。但是不需要在我的问题中公开此功能。
标签: c++ concurrency reference mutex