中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Linux系統分析死鎖的方法是什么

發布時間:2022-01-27 14:51:23 來源:億速云 閱讀:100 作者:iii 欄目:開發技術

這篇文章主要介紹“Linux系統分析死鎖的方法是什么”,在日常操作中,相信很多人在Linux系統分析死鎖的方法是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Linux系統分析死鎖的方法是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

Linux系統分析死鎖的方法是什么

產生死鎖的四個必要條件

(1) 互斥條件:一個資源每次只能被一個進程(線程)使用。 

(2) 請求與保持條件:一個進程(線程)因請求資源而阻塞時,對已獲得的資源保持不放。 

(3) 不剝奪條件 : 此進程(線程)已獲得的資源,在末使用完之前,不能強行剝奪。 

(4) 循環等待條件 : 多個進程(線程)之間形成一種頭尾相接的循環等待資源關系。

圖 1. 交叉持鎖的死鎖示意圖:

Linux系統分析死鎖的方法是什么

注釋:在執行 func2 和 func4 之后,子線程 1 獲得了鎖 A,正試圖獲得鎖 B,但是子線程 2 此時獲得了鎖 B,正試圖獲得鎖 A,所以子線程 1 和子線程 2 將沒有辦法得到鎖 A 和鎖 B,因為它們各自被對方占有,永遠不會釋放,所以發生了死鎖的現象。

使用 pstack 和 gdb 工具對死鎖程序進行分析

pstack 在 Linux 平臺上的簡單介紹

pstack 是 Linux(比如 Red Hat Linux 系統、Ubuntu Linux 系統等)下一個很有用的工具,它的功能是打印輸出此進程的堆棧信息。可以輸出所有線程的調用關系棧。

gdb 在 Linux 平臺上的簡單介紹

GDB 是 GNU 開源組織發布的一個強大的 UNIX 下的程序調試工具。Linux 系統中包含了 GNU 調試程序 gdb,它是一個用來調試 C 和 C++ 程序的調試器。可以使程序開發者在程序運行時觀察程序的內部結構和內存的使用情況 .

gdb 所提供的一些主要功能如下所示:

1 運行程序,設置能影響程序運行的參數和環境 ;

2 控制程序在指定的條件下停止運行;

3 當程序停止時,可以檢查程序的狀態;

4 當程序 crash 時,可以檢查 core 文件;

5 可以修改程序的錯誤,并重新運行程序;

6 可以動態監視程序中變量的值;

7 可以單步執行代碼,觀察程序的運行狀態。

gdb 程序調試的對象是可執行文件或者進程,而不是程序的源代碼文件。然而,并不是所有的可執行文件都可以用 gdb 調試。如果要讓產生的可執行文件可以用來調試,需在執行 g++(gcc)指令編譯程序時,加上 -g 參數,指定程序在編譯時包含調試信息。調試信息包含程序里的每個變量的類型和在可執行文件里的地址映射以及源代碼的行號。gdb 利用這些信息使源代碼和機器碼相關聯。gdb 的基本命令較多,不做詳細介紹,大家如果需要進一步了解,請參見 gdb 手冊。

清單 1. 測程序

  #include  #include  #include 
  pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER;
 
  static int sequence1 = 0;
  static int sequence2 = 0;
 
  int func1()
  {
     pthread_mutex_lock(&mutex1);
     ++sequence1;
     sleep(1);
     pthread_mutex_lock(&mutex2);
     ++sequence2;
     pthread_mutex_unlock(&mutex2);
     pthread_mutex_unlock(&mutex1);
 
     return sequence1;
  }
 
  int func2()
  {
     pthread_mutex_lock(&mutex2);
     ++sequence2;
     sleep(1);
     pthread_mutex_lock(&mutex1);
     ++sequence1;
     pthread_mutex_unlock(&mutex1);
     pthread_mutex_unlock(&mutex2);
 
     return sequence2;
  }
 
  void* thread1(void* arg)
  {
     while (1)
     {
         int iRetValue = func1();
 
         if (iRetValue == 100000)
         {
             pthread_exit(NULL);
         }
     }
  }
 
  void* thread2(void* arg)
  {
     while (1)
     {
         int iRetValue = func2();
 
         if (iRetValue == 100000)
         {
             pthread_exit(NULL);
         }
     }
  }
 
  void* thread3(void* arg)
  {
     while (1)
     {
         sleep(1);
         char szBuf[128];
         memset(szBuf, 0, sizeof(szBuf));
         strcpy(szBuf, "thread3");
     }
  }
 
  void* thread4(void* arg)
  {
     while (1)
     {
         sleep(1);
         char szBuf[128];
         memset(szBuf, 0, sizeof(szBuf));
         strcpy(szBuf, "thread3");
     }
  }
 
  int main()
  {
     pthread_t tid[4];
     if (pthread_create(&tid[0], NULL, &thread1, NULL) != 0)
     {
         _exit(1);
     }
     if (pthread_create(&tid[1], NULL, &thread2, NULL) != 0)
     {
         _exit(1);
     }
     if (pthread_create(&tid[2], NULL, &thread3, NULL) != 0)
     {
         _exit(1);
     }
     if (pthread_create(&tid[3], NULL, &thread4, NULL) != 0)
     {
         _exit(1);
     }
 
     sleep(5);
     //pthread_cancel(tid[0]);
 
     pthread_join(tid[0], NULL);
     pthread_join(tid[1], NULL);
     pthread_join(tid[2], NULL);
     pthread_join(tid[3], NULL);
 
     pthread_mutex_destroy(&mutex1);
     pthread_mutex_destroy(&mutex2);
     pthread_mutex_destroy(&mutex3);
     pthread_mutex_destroy(&mutex4);
 
     return 0;
  }

清單 2. 編譯測試程序

  [dyu@xilinuxbldsrv purify]$ g++ -g lock.cpp -o lock -lpthread

清單 3. 查找測試程序的進程號

  [dyu@xilinuxbldsrv purify]$ ps -ef|grep lock
  dyu       6721  5751  0 15:21 pts/3    00:00:00 ./lock

清單 4. 對死鎖進程第一次執行 pstack(pstack –進程號)的輸出結果

 [dyu@xilinuxbldsrv purify]$ pstack 6721
  Thread 5 (Thread 0x41e37940 (LWP 6722)):
  #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  #3  0x0000000000400a9b in func1() ()
  #4  0x0000000000400ad7 in thread1(void*) ()
  #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 4 (Thread 0x42838940 (LWP 6723)):
  #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  #3  0x0000000000400a17 in func2() ()
  #4  0x0000000000400a53 in thread2(void*) ()
  #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 3 (Thread 0x43239940 (LWP 6724)):
  #0  0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6
  #1  0x0000003d19c9a364 in sleep () from /lib64/libc.so.6
  #2  0x00000000004009bc in thread3(void*) ()
  #3  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #4  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 2 (Thread 0x43c3a940 (LWP 6725)):
  #0  0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6
  #1  0x0000003d19c9a364 in sleep () from /lib64/libc.so.6
  #2  0x0000000000400976 in thread4(void*) ()
  #3  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #4  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 1 (Thread 0x2b984ecabd90 (LWP 6721)):
  #0  0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0
  #1  0x0000000000400900 in main ()    
 
 
 清單 5. 對死鎖進程第二次執行 pstack(pstack –進程號)的輸出結果
     
  [dyu@xilinuxbldsrv purify]$ pstack 6721
  Thread 5 (Thread 0x40bd6940 (LWP 6722)):
  #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  #3  0x0000000000400a87 in func1() ()
  #4  0x0000000000400ac3 in thread1(void*) ()
  #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 4 (Thread 0x415d7940 (LWP 6723)):
  #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  #3  0x0000000000400a03 in func2() ()
  #4  0x0000000000400a3f in thread2(void*) ()
  #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 3 (Thread 0x41fd8940 (LWP 6724)):
  #0  0x0000003d19c7aec2 in memset () from /lib64/libc.so.6
  #1  0x00000000004009be in thread3(void*) ()
  #2  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #3  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 2 (Thread 0x429d9940 (LWP 6725)):
  #0  0x0000003d19c7ae0d in memset () from /lib64/libc.so.6
  #1  0x0000000000400982 in thread4(void*) ()
  #2  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #3  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 1 (Thread 0x2af906fd9d90 (LWP 6721)):
  #0  0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0
  #1  0x0000000000400900 in main ()

清單 5. 對死鎖進程第二次執行 pstack(pstack –進程號)的輸出結果

 [dyu@xilinuxbldsrv purify]$ pstack 6721
  Thread 5 (Thread 0x40bd6940 (LWP 6722)):
  #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  #3  0x0000000000400a87 in func1() ()
  #4  0x0000000000400ac3 in thread1(void*) ()
  #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 4 (Thread 0x415d7940 (LWP 6723)):
  #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  #3  0x0000000000400a03 in func2() ()
  #4  0x0000000000400a3f in thread2(void*) ()
  #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 3 (Thread 0x41fd8940 (LWP 6724)):
  #0  0x0000003d19c7aec2 in memset () from /lib64/libc.so.6
  #1  0x00000000004009be in thread3(void*) ()
  #2  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #3  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 2 (Thread 0x429d9940 (LWP 6725)):
  #0  0x0000003d19c7ae0d in memset () from /lib64/libc.so.6
  #1  0x0000000000400982 in thread4(void*) ()
  #2  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #3  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  Thread 1 (Thread 0x2af906fd9d90 (LWP 6721)):
  #0  0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0
  #1  0x0000000000400900 in main ()

顯示詳細信息

連續多次查看這個進程的函數調用關系堆棧進行分析:當進程吊死時,多次使用 pstack 查看進程的函數調用堆棧,死鎖線程將一直處于等鎖的狀態,對比多次的函數調用堆棧輸出結果,確定哪兩個線程(或者幾個線程)一直沒有變化且一直處于等鎖的狀態(可能存在兩個線程 一直沒有變化)。

輸出分析:

根據上面的輸出對比可以發現,線程 1 和線程 2 由第一次 pstack 輸出的處在 sleep 函數變化為第二次 pstack 輸出的處在 memset 函數。但是線程 4 和線程 5 一直處在等鎖狀態(pthread_mutex_lock),在連續兩次的 pstack 信息輸出中沒有變化,所以我們可以推測線程 4 和線程 5 發生了死鎖。

 Gdb into thread``輸出:

清單 6. 然后通過 gdb attach 到死鎖進程

  (gdb) info thread
   5 Thread 0x41e37940 (LWP 6722)  0x0000003d1a80d4c4 in __lll_lock_wait ()
   from /lib64/libpthread.so.0
   4 Thread 0x42838940 (LWP 6723)  0x0000003d1a80d4c4 in __lll_lock_wait ()
   from /lib64/libpthread.so.0
   3 Thread 0x43239940 (LWP 6724)  0x0000003d19c9a541 in nanosleep ()
  from /lib64/libc.so.6
   2 Thread 0x43c3a940 (LWP 6725)  0x0000003d19c9a541 in nanosleep ()
  from /lib64/libc.so.6
  * 1 Thread 0x2b984ecabd90 (LWP 6721)  0x0000003d1a807b35 in pthread_join ()
  from /lib64/libpthread.so.0

清單 7. 切換到線程 5 的輸出

 (gdb) thread 5
  [Switching to thread 5 (Thread 0x41e37940 (LWP 6722))]#0  0x0000003d1a80d4c4 in
  __lll_lock_wait () from /lib64/libpthread.so.0
  (gdb) where
  #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  #3  0x0000000000400a9b in func1 () at lock.cpp:18
  #4  0x0000000000400ad7 in thread1 (arg=0x0) at lock.cpp:43
  #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6

清單 8. 線程 4 和線程 5 的輸出

  (gdb) f 3
  #3  0x0000000000400a9b in func1 () at lock.cpp:18
  18          pthread_mutex_lock(&mutex2);
  (gdb) thread 4
  [Switching to thread 4 (Thread 0x42838940 (LWP 6723))]#0  0x0000003d1a80d4c4 in
  __lll_lock_wait () from /lib64/libpthread.so.0
  (gdb) f 3
  #3  0x0000000000400a17 in func2 () at lock.cpp:31
  31          pthread_mutex_lock(&mutex1);
  (gdb) p mutex1
  $1 = {__data = {__lock = 2, __count = 0, __owner = 6722, __nusers = 1, __kind = 0,
  __spins = 0, __list = {__prev = 0x0, __next = 0x0}},
   __size = "\002\000\000\000\000\000\000\000B\032\000\000\001", '\000'
  , __align = 2}
  (gdb) p mutex3
  $2 = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0,
  __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}},
  __size = '\000', __align = 0}
  (gdb) p mutex2
  $3 = {__data = {__lock = 2, __count = 0, __owner = 6723, __nusers = 1,
  __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}},
   __size = "\002\000\000\000\000\000\000\000C\032\000\000\001", '\000'
  , __align = 2}
  (gdb)

從上面可以發現,線程 4 正試圖獲得鎖 mutex1,但是鎖 mutex1 已經被 LWP 為 6722 的線程得到(owner = 6722),線程 5 正試圖獲得鎖 mutex2,但是鎖 mutex2 已經被 LWP 為 6723 的 得到(owner = 6723),從 pstack 的輸出可以發現,LWP 6722 與線程 5 是對應的,LWP 6723 與線程 4 是對應的。所以我們可以得出, 線程 4 和線程 5 發生了交叉持鎖的死鎖現象。查看線程的源代碼發現,線程 4 和線程 5 同時使用 mutex1 和 mutex2,且申請順序不合理。

到此,關于“Linux系統分析死鎖的方法是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

拜泉县| 河西区| 天津市| 富阳市| 龙川县| 怀远县| 临海市| 邮箱| 苍梧县| 彩票| 张家口市| 香格里拉县| 清流县| 犍为县| 渭源县| 抚顺县| 龙岩市| 荆门市| 确山县| 栾城县| 壶关县| 东乌| 黄大仙区| 汉阴县| 常德市| 武川县| 札达县| 德清县| 民乐县| 武冈市| 延边| 民权县| 栾城县| 灵台县| 肥西县| 彰化市| 曲阜市| 元氏县| 老河口市| 冕宁县| 股票|