Loading... # 一、死锁demo ```cpp #include <iostream> // 用于输入输出 #include <thread> // 用于线程创建和管理 #include <mutex> // 用于互斥锁 #include <chrono> // 用于时间操作 using std::cout; // 简化cout的调用 using std::endl; // 简化endl的调用 // 定义三个互斥锁 std::mutex mutex1; std::mutex mutex2; std::mutex mutex3; // 线程A:先锁mutex1,再锁mutex2(可能导致死锁) void FuncA() { std::cout << "FuncA Begin." << endl; std::lock_guard<std::mutex> guard1(mutex1); std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟耗时操作 std::lock_guard<std::mutex> guard2(mutex2); std::cout << "FuncA completed." << endl; } // 线程B:先锁mutex2,再锁mutex3(可能导致死锁) void FuncB() { std::cout << "FuncB Begin." << endl; std::lock_guard<std::mutex> guard2(mutex2); std::this_thread::sleep_for(std::chrono::seconds(1)); std::lock_guard<std::mutex> guard3(mutex3); std::cout << "FuncB completed." << endl; } // 线程C:先锁mutex3,再锁mutex1(可能导致死锁) void FuncC() { std::cout << "FuncC Begin." << endl; std::lock_guard<std::mutex> guard3(mutex3); std::this_thread::sleep_for(std::chrono::seconds(1)); std::lock_guard<std::mutex> guard1(mutex1); std::cout << "FuncC completed." << endl; } int main() { // 创建三个线程 std::thread t1(FuncA); std::thread t2(FuncB); std::thread t3(FuncC); // 等待所有线程完成(实际可能因死锁卡死) t1.join(); t2.join(); t3.join(); cout << "All threads finished." << endl; return 0; } ``` g++ --std=c++11 -g -O0 deadlock.cpp -o deadlock -lpthread 查看运行状态并生成coredump文件: ```cpp root@iZbp1est4y0mdt6ask7pgpZ:~# ps -aux | grep dead peter 329370 0.0 0.0 96148 1552 pts/2 Sl+ 13:55 0:00 ./deadlock root 329375 0.0 0.0 8872 656 pts/3 S+ 13:55 0:00 grep --color=auto dead root@iZbp1est4y0mdt6ask7pgpZ:~# kill -3 329370 root@iZbp1est4y0mdt6ask7pgpZ:~# **S:进程处于 休眠状态**(Interruptible Sleep),等待资源或事件触发。 **l:进程是 多线程的**(使用 clone() 系统调用创建线程)。 **+:进程是 前台进程组** 的成员(可通过 Ctrl+C 终止)。 触发产生coredump文件: peter@iZbp1est4y0mdt6ask7pgpZ:~/deadlock$ ./deadlock FuncA Begin. FuncB Begin. FuncC Begin. Quit (core dumped) ``` # 二、使用gdb来检测死锁 ```cpp ``` ## 1、info threads查看当前进程中所有线程的信息,也可以查看到部分堆栈信息 ```cpp (gdb) info thread Id Target Id Frame * 1 Thread 0x7f74738e0740 (LWP 329370) __pthread_clockjoin_ex (threadid=140138131617536, thread_return=0x0, clockid=<optimized out>, abstime=<optimized out>, block=<optimized out>) at pthread_join_common.c:145 2 Thread 0x7f74730de700 (LWP 329372) __lll_lock_wait (futex=futex@entry=0x55f8c2bbb1e0 <mutex3>, private=0) at lowlevellock.c:52 3 Thread 0x7f74728dd700 (LWP 329373) __lll_lock_wait (futex=futex@entry=0x55f8c2bbb160 <mutex1>, private=0) at lowlevellock.c:52 4 Thread 0x7f74738df700 (LWP 329371) __lll_lock_wait (futex=futex@entry=0x55f8c2bbb1a0 <mutex2>, private=0) at lowlevellock.c:52 ``` 1 是主线程, 2-3是其他线程,而且都是加锁的过程,如果在生产环境中可能有很多线程在等锁,等什么锁 ## 2、查看每个线程在等什么锁 ```cpp (gdb) thread 2 [Switching to thread 2 (Thread 0x7f74730de700 (LWP 329372))] #0 **__lll_lock_wait** (futex=futex@entry=0x55f8c2bbb1e0 <**mutex3**>, private=0) at lowlevellock.c:52 52 lowlevellock.c: No such file or directory. (gdb) bt #0 __lll_lock_wait (futex=futex@entry=0x55f8c2bbb1e0 <mutex3>, private=0) at lowlevellock.c:52 #1 0x00007f7473e2d0a3 in __GI___pthread_mutex_lock (mutex=0x55f8c2bbb1e0 <mutex3>) at ../nptl/pthread_mutex_lock.c:80 #2 0x000055f8c2bb6888 in __gthread_mutex_lock (__mutex=0x55f8c2bbb1e0 <mutex3>) at /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 #3 0x000055f8c2bb69dc in std::mutex::lock (this=0x55f8c2bbb1e0 <mutex3>) at /usr/include/c++/9/bits/std_mutex.h:100 #4 0x000055f8c2bb6a78 in std::lock_guard<std::mutex>::lock_guard (this=0x7f74730dddf0, __m=...) at /usr/include/c++/9/bits/std_mutex.h:159 #5 0x000055f8c2bb6519 in FuncB () at deadlock.cpp:28 #6 0x000055f8c2bb7658 in std::__invoke_impl<void, void (*)()> (__f=@0x55f8c4797008: 0x55f8c2bb6489 <**FuncB()**>) at /usr/include/c++/9/bits/invoke.h:60 #7 0x000055f8c2bb75f0 in std::__invoke<void (*)()> (__fn=@0x55f8c4797008: 0x55f8c2bb6489 <**FuncB()**>) at /usr/include/c++/9/bits/invoke.h:95 #8 0x000055f8c2bb7582 in std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul> (this=0x55f8c4797008) at /usr/include/c++/9/thread:244 #9 0x000055f8c2bb753f in std::thread::_Invoker<std::tuple<void (*)()> >::operator() (this=0x55f8c4797008) at /usr/include/c++/9/thread:251 #10 0x000055f8c2bb7510 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run (this=0x55f8c4797000) at /usr/include/c++/9/thread:195 #11 0x00007f7473d17cb4 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6 #12 0x00007f7473e2a609 in start_thread (arg=<optimized out>) at pthread_create.c:477 #13 0x00007f7473b53353 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95 ``` 线程2【B】在给mutex3加锁,在等mutex3 ```cpp (gdb) thread 3 [Switching to thread 3 (Thread 0x7f74728dd700 (LWP 329373))] #0 **__lll_lock_wait** (futex=futex@entry=0x55f8c2bbb160 <**mutex1**>, private=0) at lowlevellock.c:52 52 in lowlevellock.c (gdb) bt #0 __lll_lock_wait (futex=futex@entry=0x55f8c2bbb160 <mutex1>, private=0) at lowlevellock.c:52 #1 0x00007f7473e2d0a3 in __GI___pthread_mutex_lock (mutex=0x55f8c2bbb160 <mutex1>) at ../nptl/pthread_mutex_lock.c:80 #2 0x000055f8c2bb6888 in __gthread_mutex_lock (__mutex=0x55f8c2bbb160 <mutex1>) at /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 #3 0x000055f8c2bb69dc in std::mutex::lock (this=0x55f8c2bbb160 <mutex1>) at /usr/include/c++/9/bits/std_mutex.h:100 #4 0x000055f8c2bb6a78 in std::lock_guard<std::mutex>::lock_guard (this=0x7f74728dcdf0, __m=...) at /usr/include/c++/9/bits/std_mutex.h:159 #5 0x000055f8c2bb663a in FuncC () at deadlock.cpp:37 #6 0x000055f8c2bb7658 in std::__invoke_impl<void, void (*)()> (__f=@0x55f8c4797158: 0x55f8c2bb65aa <FuncC()>) at /usr/include/c++/9/bits/invoke.h:60 #7 0x000055f8c2bb75f0 in std::__invoke<void (*)()> (__fn=@0x55f8c4797158: 0x55f8c2bb65aa <**FuncC()**>) at /usr/include/c++/9/bits/invoke.h:95 #8 0x000055f8c2bb7582 in std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul> (this=0x55f8c4797158) at /usr/include/c++/9/thread:244 #9 0x000055f8c2bb753f in std::thread::_Invoker<std::tuple<void (*)()> >::operator() (this=0x55f8c4797158) at /usr/include/c++/9/thread:251 #10 0x000055f8c2bb7510 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run (this=0x55f8c4797150) at /usr/include/c++/9/thread:195 #11 0x00007f7473d17cb4 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6 #12 0x00007f7473e2a609 in start_thread (arg=<optimized out>) at pthread_create.c:477 #13 0x00007f7473b53353 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95 ``` 线程3【\*\*C】\*\*在给mutex1加锁,在等mutex1 ```cpp (gdb) thread 4 [Switching to thread 4 (Thread 0x7f74738df700 (LWP 329371))] #0 __lll_lock_wait (futex=futex@entry=0x55f8c2bbb1a0 <mutex2>, private=0) at lowlevellock.c:52 52 lowlevellock.c: No such file or directory. (gdb) bt #0 __lll_lock_wait (futex=futex@entry=0x55f8c2bbb1a0 <mutex2>, private=0) at lowlevellock.c:52 #1 0x00007f7473e2d0a3 in __GI___pthread_mutex_lock (mutex=0x55f8c2bbb1a0 <mutex2>) at ../nptl/pthread_mutex_lock.c:80 #2 0x000055f8c2bb6888 in __gthread_mutex_lock (__mutex=0x55f8c2bbb1a0 <mutex2>) at /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 #3 0x000055f8c2bb69dc in std::mutex::lock (this=0x55f8c2bbb1a0 <mutex2>) at /usr/include/c++/9/bits/std_mutex.h:100 #4 0x000055f8c2bb6a78 in std::lock_guard<std::mutex>::lock_guard (this=0x7f74738dedf0, __m=...) at /usr/include/c++/9/bits/std_mutex.h:159 #5 0x000055f8c2bb63f8 in FuncA () at deadlock.cpp:19 #6 0x000055f8c2bb7658 in std::__invoke_impl<void, void (*)()> (__f=@0x55f8c4796eb8: 0x55f8c2bb6368 <FuncA()>) at /usr/include/c++/9/bits/invoke.h:60 #7 0x000055f8c2bb75f0 in std::__invoke<void (*)()> (__fn=@0x55f8c4796eb8: 0x55f8c2bb6368 <**FuncA()**>) at /usr/include/c++/9/bits/invoke.h:95 #8 0x000055f8c2bb7582 in std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul> (this=0x55f8c4796eb8) at /usr/include/c++/9/thread:244 #9 0x000055f8c2bb753f in std::thread::_Invoker<std::tuple<void (*)()> >::operator() (this=0x55f8c4796eb8) at /usr/include/c++/9/thread:251 #10 0x000055f8c2bb7510 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run (this=0x55f8c4796eb0) at /usr/include/c++/9/thread:195 #11 0x00007f7473d17cb4 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6 #12 0x00007f7473e2a609 in start_thread (arg=<optimized out>) at pthread_create.c:477 #13 0x00007f7473b53353 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95 ``` 线程4【A】在给mutex2加锁,在等mutex2 ## 3、查看这些在等的锁是谁拥有的 ```cpp (gdb) thread 2 [Switching to thread 2 (Thread 0x7f74730de700 (LWP 329372))] #0 __lll_lock_wait (futex=futex@entry=0x55f8c2bbb1e0 <mutex3>, private=0) at lowlevellock.c:52 52 in lowlevellock.c (gdb) bt #0 __lll_lock_wait (futex=futex@entry=0x55f8c2bbb1e0 <mutex3>, private=0) at lowlevellock.c:52 #1 0x00007f7473e2d0a3 in __GI___pthread_mutex_lock (mutex=0x55f8c2bbb1e0 <mutex3>) at ../nptl/pthread_mutex_lock.c:80 #2 0x000055f8c2bb6888 in __gthread_mutex_lock (__mutex=0x55f8c2bbb1e0 <mutex3>) at /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 #3 0x000055f8c2bb69dc in std::mutex::lock (this=0x55f8c2bbb1e0 <mutex3>) at /usr/include/c++/9/bits/std_mutex.h:100 #4 0x000055f8c2bb6a78 in std::lock_guard<std::mutex>::lock_guard (this=0x7f74730dddf0, __m=...) at /usr/include/c++/9/bits/std_mutex.h:159 #5 0x000055f8c2bb6519 in FuncB () at deadlock.cpp:28 #6 0x000055f8c2bb7658 in std::__invoke_impl<void, void (*)()> (__f=@0x55f8c4797008: 0x55f8c2bb6489 <FuncB()>) at /usr/include/c++/9/bits/invoke.h:60 #7 0x000055f8c2bb75f0 in std::__invoke<void (*)()> (__fn=@0x55f8c4797008: 0x55f8c2bb6489 <FuncB()>) at /usr/include/c++/9/bits/invoke.h:95 #8 0x000055f8c2bb7582 in std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul> (this=0x55f8c4797008) at /usr/include/c++/9/thread:244 #9 0x000055f8c2bb753f in std::thread::_Invoker<std::tuple<void (*)()> >::operator() (this=0x55f8c4797008) at /usr/include/c++/9/thread:251 #10 0x000055f8c2bb7510 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run (this=0x55f8c4797000) at /usr/include/c++/9/thread:195 #11 0x00007f7473d17cb4 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6 #12 0x00007f7473e2a609 in start_thread (arg=<optimized out>) at pthread_create.c:477 #13 0x00007f7473b53353 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95 (gdb) f 3 #3 0x000055f8c2bb69dc in std::mutex::lock (this=0x55f8c2bbb1e0 <mutex3>) at /usr/include/c++/9/bits/std_mutex.h:100 100 int __e = __gthread_mutex_lock(&_M_mutex); (gdb) p mutex3 $1 = { <std::__mutex_base> = { _M_mutex = { __data = { __lock = 2, __count = 0, __owner = 329373, __nusers = 1, __kind = 0, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = "\\002\\000\\000\\000\\000\\000\\000\\000\\235\\006\\005\\000\\001", '\\000' <repeats 26 times>, __align = 2 } }, <No data fields>} ``` 进入到std::mutex::lock 这行代码所在的栈帧, 查看锁是被谁占有的,\_\_owner = **329373**, 后面如果非零,就代表这个锁被这个线程占有着。 ```cpp (gdb) info thread Id Target Id Frame 1 Thread 0x7f74738e0740 (LWP 329370) __pthread_clockjoin_ex (threadid=140138131617536, thread_return=0x0, clockid=<optimized out>, abstime=<optimized out>, block=<optimized out>) at pthread_join_common.c:145 * 2 Thread 0x7f74730de700 (LWP 329372) __lll_lock_wait (futex=futex@entry=0x55f8c2bbb1e0 <mutex3>, private=0) at lowlevellock.c:52 3 Thread 0x7f74728dd700 (LWP **329373**) __lll_lock_wait (futex=futex@entry=0x55f8c2bbb160 <mutex1>, private=0) at lowlevellock.c:52 4 Thread 0x7f74738df700 (LWP 329371) __lll_lock_wait (futex=futex@entry=0x55f8c2bbb1a0 <mutex2>, private=0) at lowlevellock.c:52 ``` 查看线程号,发现这把锁是被线程3 **329373**拿到的 这个线程2在等mutex3,而mutex3是被329373拿到的,也就是线程3 下一步干嘛? 应该去排查**329373**这个线程在干嘛 ### 3.1、线程**329373的状态** ```cpp (gdb) thread 3 [Switching to thread 3 (Thread 0x7f74728dd700 (LWP 329373))] #0 __lll_lock_wait (futex=futex@entry=0x55f8c2bbb160 <mutex1>, private=0) at lowlevellock.c:52 52 lowlevellock.c: No such file or directory. (gdb) bt #0 __lll_lock_wait (futex=futex@entry=0x55f8c2bbb160 <mutex1>, private=0) at lowlevellock.c:52 #1 0x00007f7473e2d0a3 in __GI___pthread_mutex_lock (mutex=0x55f8c2bbb160 <mutex1>) at ../nptl/pthread_mutex_lock.c:80 #2 0x000055f8c2bb6888 in __gthread_mutex_lock (__mutex=0x55f8c2bbb160 <mutex1>) at /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 #3 0x000055f8c2bb69dc in std::mutex::lock (this=0x55f8c2bbb160 <mutex1>) at /usr/include/c++/9/bits/std_mutex.h:100 #4 0x000055f8c2bb6a78 in std::lock_guard<std::mutex>::lock_guard (this=0x7f74728dcdf0, __m=...) at /usr/include/c++/9/bits/std_mutex.h:159 #5 0x000055f8c2bb663a in FuncC () at deadlock.cpp:37 #6 0x000055f8c2bb7658 in std::__invoke_impl<void, void (*)()> (__f=@0x55f8c4797158: 0x55f8c2bb65aa <FuncC()>) at /usr/include/c++/9/bits/invoke.h:60 #7 0x000055f8c2bb75f0 in std::__invoke<void (*)()> (__fn=@0x55f8c4797158: 0x55f8c2bb65aa <FuncC()>) at /usr/include/c++/9/bits/invoke.h:95 #8 0x000055f8c2bb7582 in std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul> (this=0x55f8c4797158) at /usr/include/c++/9/thread:244 #9 0x000055f8c2bb753f in std::thread::_Invoker<std::tuple<void (*)()> >::operator() (this=0x55f8c4797158) at /usr/include/c++/9/thread:251 #10 0x000055f8c2bb7510 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run (this=0x55f8c4797150) at /usr/include/c++/9/thread:195 #11 0x00007f7473d17cb4 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6 #12 0x00007f7473e2a609 in start_thread (arg=<optimized out>) at pthread_create.c:477 #13 0x00007f7473b53353 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95 (gdb) f 3 #3 0x000055f8c2bb69dc in std::mutex::lock (this=0x55f8c2bbb160 <mutex1>) at /usr/include/c++/9/bits/std_mutex.h:100 100 int __e = __gthread_mutex_lock(&_M_mutex); (gdb) p mutex1 $2 = { <std::__mutex_base> = { _M_mutex = { __data = { __lock = 2, __count = 0, __owner = 329371, __nusers = 1, __kind = 0, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = "\\002\\000\\000\\000\\000\\000\\000\\000\\233\\006\\005\\000\\001", '\\000' <repeats 26 times>, __align = 2 } }, <No data fields>} ``` 这个线程3在等mutex1,而mutex1是被329371拿到的,也就是线程4 ### 3.2、线程**329371的状态** ```cpp (gdb) thread 4 [Switching to thread 4 (Thread 0x7f74738df700 (LWP 329371))] #0 __lll_lock_wait (futex=futex@entry=0x55f8c2bbb1a0 <mutex2>, private=0) at lowlevellock.c:52 52 lowlevellock.c: No such file or directory. (gdb) bt #0 __lll_lock_wait (futex=futex@entry=0x55f8c2bbb1a0 <mutex2>, private=0) at lowlevellock.c:52 #1 0x00007f7473e2d0a3 in __GI___pthread_mutex_lock (mutex=0x55f8c2bbb1a0 <mutex2>) at ../nptl/pthread_mutex_lock.c:80 #2 0x000055f8c2bb6888 in __gthread_mutex_lock (__mutex=0x55f8c2bbb1a0 <mutex2>) at /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 #3 0x000055f8c2bb69dc in std::mutex::lock (this=0x55f8c2bbb1a0 <mutex2>) at /usr/include/c++/9/bits/std_mutex.h:100 #4 0x000055f8c2bb6a78 in std::lock_guard<std::mutex>::lock_guard (this=0x7f74738dedf0, __m=...) at /usr/include/c++/9/bits/std_mutex.h:159 #5 0x000055f8c2bb63f8 in FuncA () at deadlock.cpp:19 #6 0x000055f8c2bb7658 in std::__invoke_impl<void, void (*)()> (__f=@0x55f8c4796eb8: 0x55f8c2bb6368 <FuncA()>) at /usr/include/c++/9/bits/invoke.h:60 #7 0x000055f8c2bb75f0 in std::__invoke<void (*)()> (__fn=@0x55f8c4796eb8: 0x55f8c2bb6368 <**FuncA()**>) at /usr/include/c++/9/bits/invoke.h:95 #8 0x000055f8c2bb7582 in std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul> (this=0x55f8c4796eb8) at /usr/include/c++/9/thread:244 #9 0x000055f8c2bb753f in std::thread::_Invoker<std::tuple<void (*)()> >::operator() (this=0x55f8c4796eb8) at /usr/include/c++/9/thread:251 #10 0x000055f8c2bb7510 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run (this=0x55f8c4796eb0) at /usr/include/c++/9/thread:195 #11 0x00007f7473d17cb4 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6 #12 0x00007f7473e2a609 in start_thread (arg=<optimized out>) at pthread_create.c:477 #13 0x00007f7473b53353 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95 (gdb) f 3 #3 0x000055f8c2bb69dc in std::mutex::lock (this=0x55f8c2bbb1a0 <mutex2>) at /usr/include/c++/9/bits/std_mutex.h:100 100 int __e = __gthread_mutex_lock(&_M_mutex); (gdb) p mutex2 $3 = { <std::__mutex_base> = { _M_mutex = { __data = { __lock = 2, __count = 0, __owner = 329372, __nusers = 1, __kind = 0, __spins = 0, __elision = 0, __list = { __prev = 0x0, __next = 0x0 } }, __size = "\\002\\000\\000\\000\\000\\000\\000\\000\\234\\006\\005\\000\\001", '\\000' <repeats 26 times>, __align = 2 } }, <No data fields>} ``` 这个线程4在等mutex2,而mutex2是被329372拿到的,也就是线程2 ### 3.3、综上所述 ```cpp 这个线程2在等mutex3,而mutex3是被329373拿到的,也就是线程3 这个线程3在等mutex1,而mutex1是被329371拿到的,也就是线程4 这个线程4在等mutex2,而mutex2是被329372拿到的,也就是线程2 其中线程2 3 4分别对应thread B C A ``` 由此得出结论,出现了环形死锁的情况:  还是拿上面图举例: * 线程A已经持有mutex1,想要申请mutex2,拿到mutex2后才可以释放mutex1和mutex2,而此时mutex2被线程B占用。 * 线程B已经持有mutex2,想要申请mutex3,拿到mutex3后才可以释放mutex2和mutex3,而此时mutex3被线程C占用。 * 线程C已经持有mutex3,想要申请mutex1,拿到mutex1后才可以释放mutex3和mutex1,而此时mutex1被线程A占用。  如图,三个线程形成了一个环,死锁检测就是检查线程之间是否有环的存在。A->B, B->C, C->A 最后修改:2025 年 07 月 13 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏