死鎖:一種情形,此時執行程序中兩個或多個線程發生永久堵塞(等待),每一個線程都在等待被 html
是操做系統中預防死鎖的一種算法,這種算法資源按某種規則系統中的全部資源統一編號(例如打印機爲一、磁帶機爲二、磁盤爲三、等等),申請時必須以上升的次序。
系統要求申請進程:
一、對它所必須使用的並且屬於同一類的全部資源,必須一次申請完;
二、在申請不一樣類資源時,必須按各種設備的編號依次申請。
例如:進程PA,使用資源的順序是R1,R2;
進程PB,使用資源的順序是R2,R1;
若採用動態分配有可能造成環路條件,形成死鎖。
採用有序資源分配法:R1的編號爲1,R2的編號爲2;
PA:申請次序應是:R1,R2
PB:申請次序應是:R1,R2
這樣就破壞了環路條件,避免了死鎖的發生。
另外,還有死鎖避免,死鎖檢測與恢復等。
/** 死鎖調試 1) -g參數 2) attach 3) info threads 4) thread + number切換到對應的線程或thread apply all bt所有設置斷點 */ #include <stdio.h> #include <pthread.h> #include <unistd.h> void *workThread( void *arg ) { pthread_mutex_t mutex; pthread_mutex_init(&mutex, 0); usleep(1000*1000); fprintf(stderr,"timeout we will start dead lock\n"); pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex); } void *AliveThread ( void * arg ) { while ( true ) { usleep(1000*1000); } } int main(int argc, char *argv[]) { pthread_t alivepid; pthread_create(&alivepid,0,AliveThread,0); pthread_t deadpid; pthread_create(&deadpid, 0, workThread, 0); void *retval = 0; pthread_join(deadpid, &retval); void *retval2 = 0; pthread_join(alivepid,&retval2); return 0; }
2.編譯運行 lock.c
[root@localhost ~]# gcc -g lock.c -pthread
[root@localhost ~]# ./a.out
timeout we will start dead locklinux
(程序掛起)ios
3.查找進程idc++
[root@localhost ~]# ps -e | grep a.outredis
12826 pts/3 00:00:00 a.out //進程id爲12826算法
gdb多線程調試命令:centos
(gdb)info threads
顯示當前可調試的全部線程,每一個線程會有一個GDB爲其分配的ID,後面操做線程的時候會用到這個ID。
前面有*的是當前調試的線程。安全
(gdb)thread ID
切換當前調試的線程爲指定ID的線程。多線程
(gdb)thread apply ID1 ID2 command
讓一個或者多個線程執行GDB命令command。
(gdb)thread apply all command
讓全部被調試線程執行GDB命令command。app
(gdb)set scheduler-locking off|on|step
估計是實際使用過多線程調試的人均可以發現,在使用step或者continue命令調試當前被調試線程的時候,其餘線程也是同時執行的,怎麼只讓被調試程序執行呢?經過這個命令就能夠實現這個需求。
off 不鎖定任何線程,也就是全部線程都執行,這是默認值。
on 只有當前被調試程序會執行。
step 在單步的時候,除了next過一個函數的狀況(熟悉狀況的人可能知道,這實際上是一個設置斷點而後continue的行爲)之外,只有當前線程會執行。
//顯示線程堆棧信息
(gdb) bt
察看全部的調用棧
(gdb) f 3
調用框層次
(gdb) i locals
顯示全部當前調用棧的全部變量
4.啓動gdb attach 進程
[root@localhost ~]# gdb a.out 12826
GNU gdb (GDB) CentOS (7.0.1-45.el5.centos)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/a.out...done.
Attaching to program: /root/a.out, process 12826
Reading symbols from /lib/libpthread.so.0...(no debugging symbols found)...done.
[Thread debugging using libthread_db enabled]
[New Thread 0xb7524b90 (LWP 12828)]
[New Thread 0xb7f25b90 (LWP 12827)]
Loaded symbols for /lib/libpthread.so.0
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
0x00502402 in __kernel_vsyscall ()
(gdb) info threads //顯示全部線程信息
3 Thread 0xb7f25b90 (LWP 12827) 0x00502402 in __kernel_vsyscall ()
2 Thread 0xb7524b90 (LWP 12828) 0x00502402 in __kernel_vsyscall ()
* 1 Thread 0xb7f266c0 (LWP 12826) 0x00502402 in __kernel_vsyscall ()
(gdb) thread 2 //跳到第2個線程
[Switching to thread 2 (Thread 0xb7524b90 (LWP 12828))]#0 0x00502402 in __kernel_vsyscall ()
(gdb) bt //查看線程2的堆棧,能夠發現該線程堵塞在lock.c第17行
#0 0x00502402 in __kernel_vsyscall ()
#1 0x0072e839 in __lll_lock_wait () from /lib/libpthread.so.0
#2 0x00729e9f in _L_lock_885 () from /lib/libpthread.so.0
#3 0x00729d66 in pthread_mutex_lock () from /lib/libpthread.so.0
#4 0x080485b4 in work_thread (arg=0x0) at lock.c:17
#5 0x00727912 in start_thread () from /lib/libpthread.so.0
#6 0x0066660e in clone () from /lib/libc.so.6
(gdb)
參考自 http://blog.csdn.net/openxmpp/article/details/8615000
另外一篇:
介紹了core dump以後,來看看如何在多線程調試中使用core dump。
使用 kill 命令產生 core dump文件:
kill -11 pid
這不仍是殺掉進程嘛?沒錯,可是你用信號11殺掉它,會讓進程產生一個 Segmentation Fault,從而(若是你沒禁用 core dump 的話),致使一個 core dump。隨後你獲得一個 core 文件,裏面包含了死鎖的時候,進程的內存鏡像,也就包括了正在糾結纏綿,生離死別從而產生死鎖的那兩個,沒準是幾個,線程們的,棧。
如今知道該怎麼辦了吧?用 gdb 打開這個 core 文件,而後
thread apply all bt
gdb 會打出全部線程的棧,若是你發現有那麼幾個棧停在 pthread_wait 或者相似調用上,大體就能夠得出結論:就是它們幾個兒女情長,耽誤了整個進程。
下面我來舉一個簡單的例子(爲了代碼儘可能簡單,使用了C++11的thread library)
#include <iostream> #include <thread> #include <mutex> #include <chrono> using namespace std; mutex m1,m2; void func_2() { m2.lock(); cout<< "about to dead_lock"<<endl; m1.lock(); } void func_1() { m1.lock(); chrono::milliseconds dura( 1000 );// delay to trigger dead_lock this_thread::sleep_for( dura ); m2.lock(); } int main() { thread t1(func_1); thread t2(func_2); t1.join(); t2.join(); return 0; }
編譯代碼
$> g++ -Wall -std=c++11 dead_lock_demo.cpp -o dead_lock_demo -g -pthread
運行程序,發現程序打印出「about to dead_lock」 就不動了,如今咱們使用gdb來調試。注意gdb的版本要高於7.0,以前使用過gdb6.3調試多線程是不行的。
在這以前須要先產生core dump文件:
$> ps -aux | grep dead_lock_demo
找出 dead_lock_demo 線程號,而後:
$> kill -11 pid
此時會生成core dump 文件,在個人系統上名字就是 core
而後調試:
$> gdb dead_lock_demo core
$> thread apply all bt
下面來看一下實際的過程:
從上圖能夠看出兩個線程都阻塞在wait上,並且還給出了在哪一行代碼中,很容易就定位到產生死鎖的位置。
參考:http://www.cnblogs.com/zhuyp1015/p/3618863.html