{"id":27044788,"url":"https://github.com/berkaroad/detectlock-go","last_synced_at":"2025-04-05T05:30:07.952Z","repository":{"id":81379362,"uuid":"423178097","full_name":"berkaroad/detectlock-go","owner":"berkaroad","description":"运行时检测golang中的死锁","archived":false,"fork":false,"pushed_at":"2023-09-15T19:06:17.000Z","size":18,"stargazers_count":8,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-07-23T07:56:53.450Z","etag":null,"topics":["deadlock","go","mutex","rwmutex"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/berkaroad.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-31T14:58:47.000Z","updated_at":"2024-07-10T15:13:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"14675876-e3c1-4d63-8d9e-08a67b239907","html_url":"https://github.com/berkaroad/detectlock-go","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/berkaroad%2Fdetectlock-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/berkaroad%2Fdetectlock-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/berkaroad%2Fdetectlock-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/berkaroad%2Fdetectlock-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/berkaroad","download_url":"https://codeload.github.com/berkaroad/detectlock-go/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247293912,"owners_count":20915327,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deadlock","go","mutex","rwmutex"],"created_at":"2025-04-05T05:30:07.177Z","updated_at":"2025-04-05T05:30:07.885Z","avatar_url":"https://github.com/berkaroad.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DetectLock-go\n\n用于检测运行时死锁。获得产生死锁的goroutine编号后，结合go-pprof的堆栈信息，即可找到代码相关位置。\n\ngoroutine的锁信息记录，采用分片锁，降低了多线程并发竞争的性能影响。\n\n- 支持 `sync.Mutex`、`sync.RWMutex`\n\n- 支持检测 `锁重入`、`多把锁顺序不一致导致的互锁`\n\n- 支持 启用 / 禁用 调试功能。\n\n## 用法\n\n```go\nimport (\n    \"github.com/berkaroad/detectlock-go\"\n)\n\n// 应用启动时，设置启用调试\ndetectlock.EnableDebug()\n\n// 声明 sync.Mutex、sync.RWMutex 替换为 detectlock.Mutex、detectlock.RWMutex\nvar locker1 *detectlock.Mutex = \u0026detectlock.Mutex{}\nvar locker2 *detectlock.RWMutex = \u0026detectlock.RWMutex{}\n\n// 异步检测死锁\nitems := detectlock.Items()\nfmt.Println(detectlock.DetectAcquired(items)) // 检测获得锁的goroutine列表\nfmt.Println(detectlock.DetectReentry(items)) // 检测锁重入的goroutine列表\nfmt.Println(detectlock.DetectLockedEachOther(items)) // 检测互锁的goroutine列表\n\n// 关闭调试，并清理锁使用信息\ndetectlock.DisableDebug()\n```\n\n## 数据格式\n\n`goroutine \u003c协程ID\u003e: [(\u003c锁标识\u003e, \u003c锁状态\u003e, \u003c调用者函数\u003e(file: \u003c源码文件名\u003e:\u003c源码行号\u003e)), ...]`\n\n- 锁标识：相同标识即为同一把锁。\n\n- 锁状态，共4种：\n\n  - acquired\n\n    获得Mutex锁，或RWMutex写锁。\n\n  - wait\n\n    等待Mutex锁，或等待RWMutex写锁。\n\n  - r-acquired\n\n    获得RWMutex读锁。\n\n  - r-wait\n\n    等待RWMutex读锁。\n\n- 调用者函数\n\n  调用了加锁操作的调用者的函数名，包含所属的包名。\n\n- 源码文件名\n\n  调用了加锁操作的调用者的函数所在的源文件名。\n\n- 源码行号\n\n  调用了加锁操作的调用者的函数所在的源文件中的行号。\n\n## 检测到死锁的示例\n\n- 检测 sync.Mutex 多把锁顺序不一致导致的互锁\n\n```plain\n--- DetectAcquired ---\ngoroutine 29: [(0xc0000b4008, acquired, main.B (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex01/main.go:30)), (0xc0000b4000, wait, main.B (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex01/main.go:33))]\ngoroutine 30: [(0xc0000b4000, acquired, main.A (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex01/main.go:20)), (0xc0000b4008, wait, main.A (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex01/main.go:23))]\n\n--- DetectLockedEachOther ---\ngoroutine 29: [(0xc0000b4008, acquired, main.B (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex01/main.go:30)), (0xc0000b4000, wait, main.B (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex01/main.go:33))]\ngoroutine 30: [(0xc0000b4000, acquired, main.A (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex01/main.go:20)), (0xc0000b4008, wait, main.A (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex01/main.go:23))]\n\n```\n\n- 检测 sync.Mutex 锁重入\n\n```plain\n--- DetectAcquired ---\ngoroutine 53: [(0xc0000160b8, acquired, main.C (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex02/main.go:19)), (0xc0000160b8, wait, main.C (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex02/main.go:22))]\n\n--- DetectReentry ---\ngoroutine 53: [(0xc0000160b8, acquired, main.C (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex02/main.go:19)), (0xc0000160b8, wait, main.C (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex02/main.go:22))]\n\n```\n\n- 检测 sync.Mutex、sync.RWMutex 多把锁顺序不一致导致的互锁\n\n```plain\n--- DetectAcquired ---\ngoroutine 8: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 10: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 13: [(0xc0000160b8, acquired, main.E (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:30)), (0xc0000180c0, wait, main.E (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:33))]\ngoroutine 14: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 16: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 50: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 52: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 54: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 56: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 58: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\n\n--- DetectLockedEachOther ---\ngoroutine 8: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 10: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 13: [(0xc0000160b8, acquired, main.E (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:30)), (0xc0000180c0, wait, main.E (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:33))]\ngoroutine 14: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 16: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 50: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 52: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 54: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 56: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\ngoroutine 58: [(0xc0000180c0, r-acquired, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:21)), (0xc0000160b8, wait, main.D (file: /home/berkaroad/github/berkaroad/detectlock-go/examples/mutex03/main.go:24))]\n\n```\n\n## Benchmark\n\n通过对 `启用调试` 、`禁用调试` 、 `原生` 的锁操作的性能对比，`启用调试` 模式下性能比较差，因此不适合用于生产环境。而对于 `禁用调试` 、 `原生` 的对比，性能损耗相差无几。\n\n```sh\nmake go-bench\n```\n\n```plain\nGO111MODULE=on GOPROXY=https://goproxy.cn,direct go test -run=none -count=1 -benchtime=10000x -benchmem -bench=. ./... | grep Benchmark\nBenchmarkMutex_Lock/EnableDebug-4                  10000             97118 ns/op            5928 B/op         75 allocs/op\nBenchmarkMutex_Lock/DisableDebug-4                 10000               462.6 ns/op           160 B/op         10 allocs/op\nBenchmarkMutex_Lock/sync.Mutex-4                   10000               401.7 ns/op           160 B/op         10 allocs/op\nBenchmarkMutex_TryLock/EnableDebug-4               10000            103766 ns/op            5928 B/op         75 allocs/op\nBenchmarkMutex_TryLock/DisableDebug-4              10000               447.7 ns/op           160 B/op         10 allocs/op\nBenchmarkMutex_TryLock/sync.Mutex-4                10000               391.4 ns/op           160 B/op         10 allocs/op\nBenchmarkRWMutex_RLock/EnableDebug-4               10000            102587 ns/op            5928 B/op         75 allocs/op\nBenchmarkRWMutex_RLock/DisableDebug-4              10000               603.0 ns/op           160 B/op         10 allocs/op\nBenchmarkRWMutex_RLock/sync.RWMutex-4              10000               415.0 ns/op           160 B/op         10 allocs/op\nBenchmarkRWMutex_TryRLock/EnableDebug-4            10000            413464 ns/op            6090 B/op         70 allocs/op\nBenchmarkRWMutex_TryRLock/DisableDebug-4           10000               407.6 ns/op           160 B/op         10 allocs/op\nBenchmarkRWMutex_TryRLock/sync.RWMutex-4           10000               428.3 ns/op           160 B/op         10 allocs/op\nBenchmarkRWMutex_Lock/EnableDebug-4                10000            101591 ns/op            5928 B/op         75 allocs/op\nBenchmarkRWMutex_Lock/DisableDebug-4               10000               544.3 ns/op           160 B/op         10 allocs/op\nBenchmarkRWMutex_Lock/sync.RWMutex-4               10000               875.6 ns/op           160 B/op         10 allocs/op\nBenchmarkRWMutex_TryLock/EnableDebug-4             10000            102170 ns/op            5928 B/op         75 allocs/op\nBenchmarkRWMutex_TryLock/DisableDebug-4            10000               471.0 ns/op           160 B/op         10 allocs/op\nBenchmarkRWMutex_TryLock/sync.RWMutex-4            10000               456.1 ns/op           160 B/op         10 allocs/op\n\n```\n\n## 发布版本\n\n### v1.0.1 (2023-09-16)\n\n- 加锁时，额外收集调用者函数栈\n\n  用于问题诊断时，可以看到调用者的函数完整名、代码行。\n\n- 补全 `sync.Mutex`、`sync.RWMutex`\n\n  补充缺失的函数： `TryLock()`、`TryRLock()`。\n\n- 优化了未开启调试场景下，默认不占用10Mb内存\n\n### v1.0 (2021-10-31)\n\n- 支持 `sync.Mutex`、`sync.RWMutex`；\n\n- 支持检测 `锁重入`、`多把锁顺序不一致导致的互锁`；\n\n- 支持 启用 / 禁用 调试功能。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fberkaroad%2Fdetectlock-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fberkaroad%2Fdetectlock-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fberkaroad%2Fdetectlock-go/lists"}