(导致两个问题的问题)
在C++11中,锁是原子的,其中一个绝对可以确保两个线程不能同时获得锁?
如果以上答案是“是”,那么双重检查锁定的目的是什么?
最后,为什么我们需要std:: lock (),因为我们可以只使用原子原语(很明显,我们知道它是原子),并根据是否获得锁而将其设置为1或0?
发布于 2013-09-15 22:56:16
双重检查锁定背后的混淆思想是:而不是在检查条件时获得一个锁,并且只在不太可能的情况下获得锁。然而,要使这个工作正常进行,仍然需要相当多的同步,这是相当容易出错的。由于双重检查锁定的主要用途是初始化单个对象(这本身并不理想)和线程间共享的常量对象,因此C++11实际上实现了函数本地static对象的线程安全初始化。这应该消除大多数情况下,人们试图获得双重检查锁定的权利。
除此之外,互斥锁的要点是最多一个线程可以获得互斥锁,即保证没有两个线程可以获得相同的锁。关于使用原子变量来表示类似锁的内容,您需要注意,锁定/解锁互斥锁会增加额外的同步,而不是通过更改原子值来完成的:仅仅知道只有一个线程正在修改共享状态是不够的,还需要向系统发出信号。此外,当无法获得锁时,普通锁可能挂起线程执行(虽然我不认为实现是必需的,也就是说,我认为它可以使用自旋锁进行繁忙的等待)。
发布于 2013-09-15 22:55:54
锁是100%的原子,除非你试图做一些聪明的事情,比如在别人获得锁的时候摧毁一个锁。
锁定需要时间。如果您只需要检查锁的一小部分时间,二次检查锁定可以让您避免锁定成本,只有当您不能证明跳过锁是安全的锁。
您不能简单地用原子原语替换锁,因为您可以等待锁。如果您等待一个锁,操作系统将停止运行该线程,并将其CPU资源用于其他地方。如果你坐在原子基元上循环,你会让CPU忙,而不做有用的事情。
话虽如此,有一个锁结构的方式,称为自旋锁,这是非常快,如果你可以预期它只锁定几个周期。
此外,不能将condition_variables与原子变量一起使用,您需要真正的锁
发布于 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()通过等待线程获得两个互斥变量而避免了这一点,而不阻止其他线程同时锁定它们。
https://stackoverflow.com/questions/18818248
复制相似问题