C++ 线程的学习---线程死锁
因为是学习篇,写下是为了个人的学习与理解。故参考其他文章为多。
- 为什么会有死锁?
想象一下这样的情况,thread A 在run的时候需要等待thread B的结果,也就是threadprocA中添加tB.join(), 在thread B的threadProcB中添加tA.join()。结果就是线程A在死等线程B的结果,而线程B也在死等线程A的结果。这样就造成了死锁。
另一个例子: 两个线程争互斥锁:每一个线程需要去锁定一对互斥锁(mutex)去执行一个任务,一个线程已经获取了一个互斥锁(mutex),另一个也获取了一个互斥锁(mutex),每一个线程都在等待锁定另一个互斥锁(mutex),这样造成的结果是任何一个线程都无法得到另一个互斥锁(mutex)。这种就叫死锁(deadlock),这里最大的问题是完成任务必须锁定两个或多个互斥锁(mutex)来执行操作。
- 避免死锁的一般准则:
线程死锁只发生在有锁的情况下。有时你创建了两个个线程,这两个线程分别join另一个线程,这样任何join都无法返回,每个线程都在等待另一个线程结束,这就是两个孩子为了玩具打架一样。这种的问题可以发生在任何“一个线程正在等另一个线程做事,而另一个线程有时候也会等第一个线程做什么事”的时候。避免线程死锁归结为一个重要概念就是:A线程不要等待B线程,如果B线程有可能等待A线程。
- 避免嵌套锁定
这一条是最简单的,你已经锁定了一个mutex的时候,你最好不要再次锁定。如果你遵守了这条规则,因为一个线程只有一个锁的情况下不会造成死锁。但是也有其它原因会造成死锁(比如一个线程在等待另一个线程),如果你要锁定多个,你就用std::lock。
2. 在已经持有锁的时候不要调用用户自义的代码
因为用户自定义的代码是无法预知的,谁知道他的代码里会不会也想要锁定这个lock。有时候无法避免不调用用户定义代码,这种情况下,你需要注意。
3. 按固定顺序锁定
如果你要锁定两个以上的mutex而你又不能用std::lock。那么最好的建议就按固定顺序去锁定。
4. 用层锁来防止死锁
hierarchical_mutex规则思想是:将mutex分层,规定加锁顺序是由高层到底层才能进行,底层到高层报出运行时错误,这样就可以利用编程的方法检测死锁。
文章参考: c++多线程-线程中的死锁问题