首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++11多线程锁和原子原语

C++11多线程锁和原子原语
EN

Stack Overflow用户
提问于 2013-09-15 22:45:49
回答 3查看 1.2K关注 0票数 1

(导致两个问题的问题)

在C++11中,锁是原子的,其中一个绝对可以确保两个线程不能同时获得锁?

如果以上答案是“是”,那么双重检查锁定的目的是什么?

最后,为什么我们需要std:: lock (),因为我们可以只使用原子原语(很明显,我们知道它是原子),并根据是否获得锁而将其设置为1或0?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-09-15 22:56:16

双重检查锁定背后的混淆思想是:而不是在检查条件时获得一个锁,并且只在不太可能的情况下获得锁。然而,要使这个工作正常进行,仍然需要相当多的同步,这是相当容易出错的。由于双重检查锁定的主要用途是初始化单个对象(这本身并不理想)和线程间共享的常量对象,因此C++11实际上实现了函数本地static对象的线程安全初始化。这应该消除大多数情况下,人们试图获得双重检查锁定的权利。

除此之外,互斥锁的要点是最多一个线程可以获得互斥锁,即保证没有两个线程可以获得相同的锁。关于使用原子变量来表示类似锁的内容,您需要注意,锁定/解锁互斥锁会增加额外的同步,而不是通过更改原子值来完成的:仅仅知道只有一个线程正在修改共享状态是不够的,还需要向系统发出信号。此外,当无法获得锁时,普通锁可能挂起线程执行(虽然我不认为实现是必需的,也就是说,我认为它可以使用自旋锁进行繁忙的等待)。

票数 4
EN

Stack Overflow用户

发布于 2013-09-15 22:55:54

锁是100%的原子,除非你试图做一些聪明的事情,比如在别人获得锁的时候摧毁一个锁。

锁定需要时间。如果您只需要检查锁的一小部分时间,二次检查锁定可以让您避免锁定成本,只有当您不能证明跳过锁是安全的锁。

您不能简单地用原子原语替换锁,因为您可以等待锁。如果您等待一个锁,操作系统将停止运行该线程,并将其CPU资源用于其他地方。如果你坐在原子基元上循环,你会让CPU忙,而不做有用的事情。

话虽如此,有一个锁结构的方式,称为自旋锁,这是非常快,如果你可以预期它只锁定几个周期。

此外,不能将condition_variables与原子变量一起使用,您需要真正的锁

票数 2
EN

Stack Overflow用户

发布于 2013-09-16 07:43:42

是的,C++11锁是原子的:一次只能有一个线程在单个std::mutex上拥有一个锁。这就是互斥的全部意义:提供互斥。

双重检查锁定的目的是避免在不需要锁时获取锁的开销:特别是对于,当多线程并发运行同一位代码时避免、互斥和随后的序列化,并且不再需要互斥。

这通常用于某种形式的一次性初始化,并且仍然需要同步.这种同步可以用atomics来完成,但是很难做到。在我写的博客文章(使用Atomics的延迟初始化和双重检查锁定)中,我确实提到了如何做到这一点,但通常情况下,您最好只使用本地static对象或std::call_once

在某些情况下,可以用原子标志替换Mutexe,但是很难实现同步:通常,标记只是表示可以访问其他数据,您需要确保这些数据是正确同步的。除非分析表明互斥是瓶颈,否则最好坚持互斥,而不是尝试与atomics同步。

最后,std::lock()的主要目的是在没有死锁的情况下一次锁定多个互斥体。通常你必须一次锁一个互斥锁。但是,如果线程1锁定互斥锁A,则互斥锁B,而线程2锁定互斥锁B,那么互斥锁A就会导致死锁。std::lock()通过等待线程获得两个互斥变量而避免了这一点,而不阻止其他线程同时锁定它们。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18818248

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档