线程安全std :: map:锁定整个地图和各个值[重复]
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程安全std :: map:锁定整个地图和各个值[重复]相关的知识,希望对你有一定的参考价值。
这个问题在这里已有答案:
struct Data
{
...
CRITICAL_SECTION valLock;
}
std::map<int, Data> mp;
CRITICAL_SECTION mpLock;
我目前正在使用两个关键部分来使这个线程安全。
我必须锁定map
和Data
更新Data
//Lock mpLock
//Lock mp[key1].valLock
mp[key1].something = something_new;
//unlock mp[key1].valLock
//unlock mpLock
我查看了intel的并发hashmap,它不需要两个锁并在内部处理它。如果我不想使用intel的tbb,还有其他方法。我只有c++ 98
支持。虽然可以使用boost
。看看boost::shared_mutex
,但无法解释我如何在当前场景中使用它。
编辑:真的需要锁定容器吗?我不能使用Data::valLock
来读/写Data
。在mp
中的任何插入都不会影响现有的迭代器,因此不需要锁定。任何从mp
删除都将在Data::valLock
之前。这里可能会错过哪些案例?
编辑2:
UpdateThread()
{
//Lock mp[key].valLock
mp[key].a = b; //Line 1
//unlock mp[key].valLock
}
ReadThread()
{
//Lock mp[key].valLock
something = mp[key].a; //Line 2
//unlock mp[key].valLock
}
所以我认为第2行只能在第1行完成时执行(反之亦然),即mp
已经更新(以及地图内部)。那么它不安全吗?如果不是那么这意味着如果一个线程修改了mp [key1],而另一个线程读取了mp [key2],这是数据竞争?
需要一个互斥锁才能使容器具有线程安全性。并且每个对象的互斥锁使这些对象中的每一个都是线程安全的。
每个对象的互斥体是次优设计。另一种设计是使用可复制但不可变的对象或在容器中存储共享/侵入指针。
使用不可变对象,读取器锁定容器(用于读取),制作元素的副本并解锁容器。作家锁定容器(用于写入)添加/删除/修改元素并解锁。因为读者总是复制元素,所以元素上的线程之间永远不会发生争用。
使用共享指针,读者可以执行上述操作。作者也如上所述,而不是修改现有元素,作家总是创建一个新元素并替换现有元素。
不可变对象的示例:
template<class Key, class Value>
class ThreadSafeMap
{
std::mutex m_;
std::map<Key, Value> c_;
public:
Value get(Key const& k) {
std::unique_lock<decltype(m_)> lock(m_);
return c_[k]; // Return a copy.
}
template<class Value2>
void set(Key const& k, Value2&& v) {
std::unique_lock<decltype(m_)> lock(m_);
c_[k] = std::forward<Value2>(v);
}
};
您可能还想使用std::unordered_map
(或开源代码)代替std::map
来获得更好的性能。 std::map
相当缓存不友好。
真的需要锁定容器吗?
是
我不能使用Data :: valLock来读/写数据。
当然你可以,这已经是你正在使用它。
mp中的任何插入都不会影响现有的迭代器,因此不需要锁定
错误。
插入映射不会使现有迭代器无效,但如果您同时插入或删除两个线程(或者一个线程插入/删除和另一个线程查找),则不安全。这不是因为迭代器失效,而是因为更新和遍历内部节点指针图不能同时安全地完成。
任何其他基于节点的容器都可能是这样。
现在,如果在保持容器锁的同时获得(并保留)映射到地图的迭代器,只要迭代器没有失效,您就可以通过该迭代器继续引用该单个节点而不保持容器锁。这可以。
如果你想对除迭代之外的迭代器做任何事情,那么你需要再次使用容器锁。推进迭代器或找到另一个迭代器,两者都必须遍历节点图(如果你没有持有锁),可能会由另一个执行插入或删除的线程在你的下面进行变异。
以上是关于线程安全std :: map:锁定整个地图和各个值[重复]的主要内容,如果未能解决你的问题,请参考以下文章
如何以线程安全的方式使用`std::unordered_map`?