【发布时间】:2020-04-02 13:42:22
【问题描述】:
所以,我有一个 std::map 对象,它同时被多个线程访问,我决定使用 unique_lock 来确保映射操作安全。
在一个线程的实现中,地图对象被一些函数使用(这些函数通常从地图对象中添加/删除项目),所以我想知道在父函数的顶部定义 unique_lock 是否可以保证安全 ?或者我需要将它添加到这些功能中的每一个?
void Thread1() {
std::unique_lock<std::mutex> ul(mutex);
func1(); // map object is getting changed here
func2(); // map object is getting changed here
}
【问题讨论】:
-
只要一个互斥锁被锁定,它就不能被任何其他试图锁定同一个互斥锁的线程锁定。因此,这可能是一个“同步惩罚”,它会减慢您的并发执行速度。锁应尽可能紧密地封闭对共享数据的每次访问。您可以公开minimal reproducible example 以获得更具体的答案。
-
一般情况下,您希望在尽可能靠近临界区的位置创建和销毁
unique_lock。这意味着将其放在每个func1和func2中,仅围绕访问您的地图的部分。确保也将它放在读取访问权限周围(或者使用读/写锁,而不是使用底层shared_mutex以及shared_lock和unique_lock的组合来获取访问权限)。 -
感谢@Scheff 和 JohnFilleau 的回复。但是抛开代码优化不谈,这个逻辑能保证安全吗?
-
嗯。对抗比赛条件的安全性?是的。死锁怎么办?一个线程尝试写入,但在填充缓冲区时从不解锁。另一个线程尝试读取但正在等待锁定。失败是安全的(从用户的角度来看)。而且,顺便说一句。如果我不打算通过并发来获得性能/加速... ;-)
-
另外,您可以为每个线程提供一个单独的映射(或缓冲区或其他)来填充,并在加入所有线程后合并结果。所以,你不需要任何同步。 (除了在每个线程的启动和加入时您已经拥有(并且无法阻止)的那个),即您不需要互斥锁。对于您的问题,这可能是最安全、甚至最快的解决方案。
标签: c++ multithreading mutex