对在 std::map 的查找/插入上使用可升级锁感到困惑
confusion over using upgradable lock on std::map's find/insert
考虑一个线程安全的getter方法,它的形式相对来说是最简单的:
std::map<std::string, boost::shared_ptr<AAA> > repo;
AAA & get(const std::string &key)
{
boost::upgrade_lock<boost::shared_mutex> lock(repoMutex);
std::map<std::string, boost::shared_ptr<AAA> >::iterator it = repo.find(key);
if(it == repo.end()){
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
boost::shared_ptr<AAA> t(new AAA(key));
repo.insert(std::make_pair(key,t));
return *t;
}
return *it->second;
}
在上面,我使用共享(可升级)锁来保护查找操作,并且只有在需要插入密钥/值时才升级到唯一锁。到目前为止还不错吗?
我的想法如下(如果在任何步骤中我的概念是错误的,请告诉我):
两个线程进入方法
允许两者同时为同一个密钥运行
repo.find()
(并且该密钥不存在)。两个都失败了。因为密钥不存在。
第一个线程通过进入升级区域获得独占访问,而等待进入升级区域的第二个
第一个线程完成为key创建新条目的工作,然后离开。
第二个线程进入,覆盖第一个线程插入的键/值。(这不是任何人想要的)
我们如何解决这个问题?感谢
简而言之,您当前的解决方案几乎没有任何问题。
首先,第二个线程不会覆盖第一个线程写入的数据,因为map::insert()只插入新的键。您只需要检查insert
是否真的插入了元素并返回相应的值。
唯一令人担忧的是可能不必要地免费创建t
。在这种情况下,您可以在锁定后添加另一个检查:
std::map<std::string, boost::shared_ptr<AAA> >::iterator it = repo.find(key);
if(it == repo.end()){
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
if (repo.find(key) == repo.end() {
...
}
}
但是你应该对你的代码进行评测,看看这是否给你带来了优势。
此外,您可以使用带有提示的map::insert()
来避免重复搜索密钥:
std::map<std::string, boost::shared_ptr<AAA> >::iterator it = repo.find(key);
if(it == repo.end()){
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
it = repo.lower_bound(key);
if (it->first != key)
boost::shared_ptr<AAA> t(new AAA(key));
repo.insert(it, std::make_pair(key,t));
return *t;
} else {
return *it->second;
}
}
相关文章:
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- 使用重载 [] 运算符返回 std::map() 的可赋值
- 有没有办法从map::find()获得提升::可选结果?
- Visual Studio 2017 STL 可视化工具失败了一个 std::map<MyIntrusivePtr, std::tuple<....> >
- 类模板参数扣除是否可与STD :: MAP一起使用
- 使用MAP ITERETER可使用不良的存储器
- 使用 std::string 参数和不可移动/可复制参数构建 std::map
- 什么是二进制可升级性
- std::multiset vs. std::<int>map<int, std::size_t> 用于保留多个可重复的整数值
- 提升升级可锁定概念
- 有没有一种方法可以为std::map中小于给定键的第一个元素找到反向迭代器
- 对在 std::map 的查找/插入上使用可升级锁感到困惑
- map/set迭代器不是可解引用的c++ map
- 互斥锁的可升级所有权如何影响其他线程
- 可视化如何做我遍历 std::map<std::string,shared_ptr<A>> 在 C++ 中的元素
- 可升级和基于插件的应用程序开发
- 为什么共享锁只能持有一个可升级锁
- Map迭代器可用于begin(),但不能用于rbegin()
- 这个可移动类型对于 std::map 有什么问题?
- C++ 提升::线程可升级互斥"try upgrade lock"?