我对多线程仍然很陌生,但已经被烧了好几次了。 现在我试图避免一些陷阱,但我很难处理以下内容:
考虑几个线程,Thread A
Producer,因此是 writer
,Thread B
,C
,...消费者线程因此 reader
。
所有共享一个公共(public)缓冲区 S
一些基础书籍建议为这种情况引入所谓的ReadWriteLock
。
多个并发读取是可能的,但显然只有一个写入。Boost 提供了这样的锁,Qt 也是如此。
让我们假设两个函数 f1 和 f2 锁定 S 以供读取。
在线程 B
中调用 f1 并锁定读取,在 f1 内部调用 f2 并锁定再次读取,因此 嵌套锁定 是可能的。
现在考虑执行 f1 并第一次锁定读取的瞬间。如果线程 A 被调用并想要写入,他将被阻塞。
此外,如果在 f1 内部调用 f2 并希望锁定它,因为阻塞的 writer
正在等待,在这种情况下,许多锁(例如 QReadWriteLock
)进一步阻塞 读者
也是如此。
因此,我们得到了一个非常讨厌的死锁,它是不可预测的,只有当 writer
在 f1 的锁和 f2 的锁之间踢进来时才会发生。
我目前避免此类错误的方法是使用调试工具来跟踪锁定并断言同一线程是否两次尝试锁定以进行读取,但这非常麻烦。 除此之外,我避免将太多代码放入锁中,这会有所帮助,但可能会被我团队的其他成员忽略。
可以使用哪些其他功能来防止此类情况发生? 为什么 ReadWriteLocks 完全允许它们? 在设计阶段是否有一些通用的经验法则可以避免上述情况?
预先感谢您阅读这个长问题;-)
最佳答案
也许您可以使用 QReadWriteLock 中的 tryReadLock 函数。以防止死锁。
如果锁定读取失败.. 则解锁读取互斥体。
在某些情况下,它可能会丢失读取的数据,如果您不想丢失任何读取的数据,可以通过放置标志或 ID 号或其他东西来识别您失败的读取作业并将其放入stack 所以在写线程完成他的工作后,你将能够从失败的开始恢复你的读取内容。它会尽量减少你丢失数据..
希望对您有所帮助。
抱歉我的英语不好。
关于c++ - 了解并避免多线程应用程序中嵌套锁的危险,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9245199/