8 个稳定版本
1.3.2 | 2023年11月19日 |
---|---|
1.3.1 | 2023年10月3日 |
1.3.0 | 2021年8月16日 |
1.2.0 | 2021年2月27日 |
1.0.0 | 2020年2月26日 |
#101 在 并发
38 次每月下载
用于 4 crates
37KB
909 行
no_deadlocks
: 运行时死锁调试器
Rust 很棒,但当前的 std::sync
API 不包含用于避免死锁的内存安全函数。这个crate旨在提供一个相同的API以方便切换,但你得到的是反死锁的锁,而不是Rust通常的锁。
默认情况下,当发现死锁时,调试信息将写入 stderr
。如果您想将 no_deadlock
报告写入特定文件,您可以在 NO_DEADLOCKS
环境变量中指定其路径。
为什么我要使用这个crate?
它很容易使用,因为API与Rust的 std::sync
相同,但你得到的是自我调试的锁,太棒了!
您可以在创建程序时预防性地使用它,或者当您怀疑发生死锁并想进行调查时,可以随时用这些锁替换您的锁。
那么为什么我还要继续使用Rust的 std::sync
呢?
因为等价交换定律非常明确:通过获得这些出色的自我调试特性,您会失去一些性能:我提供的锁将会更慢(实际上会慢得多),因为它们都需要报告给同一个管理器以实现可调试性。
作为一个经验法则,我建议在将 use no_deadlocks::...
转换为其 std::sync
等价物之前,先使用 no_deadlocks
调试您的应用程序。
请记住,死锁与时间问题密切相关,您可能不会系统性地遇到这些问题,所以请务必进行彻底的测试 :)
它是如何工作的?
no_deadlocks
的所有锁实际上都是全局 LockManager
元素的句柄。它们的状态存储在一个单独的集合中,每当您的锁被锁定或解锁时,这个集合都会被锁定和修改。
当获取锁时,将保存一个未解决的跟踪以备调试需要,并将其与线程ID一起存储。在解锁时丢弃这些信息。
当锁不可用时,请求将存储一个未解决的跟踪,并执行分析。
本分析构建了一个图,其中锁指向当前拥有它们的线程,而线程则指向它们已请求的锁。
使用简单的回溯算法来搜索图中的循环。
如果检测到循环,则表示存在死锁:然后将相关跟踪解决,以帮助您了解死锁发生的原因。
关于重入呢?
虽然这个crate可以处理重入,但std::sync
的锁则不行。重入实际上是在使用锁时可以找到的最简单的死锁之一,并且通常可以避免。然而,这却是一个容易犯的错误,尤其是在使用递归时。
no_deadlock
以与所有其他死锁相同的方式检测重入死锁,但会略有不同地记录,因为它很容易区分(重入死锁由一个2节点循环表示,而任何其他死锁都需要更多节点来表示)。
为什么默认使用vector-map
?
因为在大多数程序中,实际上锁的数量相当少。vector-map
的VecMap
被构建为与std::collections::HashMap
等价的元组向量,这对于小型集合来说更有效。
use_vecmap
功能(默认开启)在VecMap
和HashMap
之间切换。如果您的程序使用了许多锁(大约有一百个),您可以随时将其关闭。
这个crate的下一步是什么?
我对这个crate的当前状态感到满意(即:“我没有计划”),但您可以随时提交一个问题,让我知道您的想法:)
依赖关系
~2.4–4MB
~77K SLoC