成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

在Linux上,你做死鎖分析的簡單方法

系統 Linux 系統運維
死鎖 (deallocks): 是指兩個或兩個以上的進程(線程)在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處于死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程(線程)稱為死鎖進程(線程)。 由于資源占用是互斥的,當某個進程提出申請資源后,使得有關進程(線程)在無外力協助下,永遠分配不到必需的資源而無法繼續運行,這就產生了一種特殊現象死鎖。

簡介

死鎖 (deallocks): 是指兩個或兩個以上的進程(線程)在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處于死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程(線程)稱為死鎖進程(線程)。 由于資源占用是互斥的,當某個進程提出申請資源后,使得有關進程(線程)在無外力協助下,永遠分配不到必需的資源而無法繼續運行,這就產生了一種特殊現象死鎖。

一種交叉持鎖死鎖的情形,此時執行程序中兩個或多個線程發生***堵塞(等待),每個線程都在等待被其它線程占用并堵塞了的資源。例如,如果線程 1 鎖住了記錄 A 并等待記錄 B,而線程 2 鎖住了記錄 B 并等待記錄 A,這樣兩個線程就發生了死鎖現象。在計算機系統中 , 如果系統的資源分配策略不當,更常見的可能是程序員寫的程序有錯誤等,則會導致進程因競爭資源不當而產生死鎖的現象。

產生死鎖的四個必要條件

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

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

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

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

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

 

 

 

交叉持鎖的死鎖

 

注釋:在執行 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. 測試程序

  1. #include <unistd.h>  
  2. #include <pthread.h>  
  3. #include <string.h>  
  4.  
  5. pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;  
  6. pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;  
  7. pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;  
  8. pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER;  
  9.  
  10. static int sequence1 = 0;  
  11. static int sequence2 = 0;  
  12.  
  13. int func1()  
  14. {  
  15.    pthread_mutex_lock(&mutex1);  
  16.    ++sequence1;  
  17.    sleep(1);  
  18.    pthread_mutex_lock(&mutex2);  
  19.    ++sequence2;  
  20.    pthread_mutex_unlock(&mutex2);  
  21.    pthread_mutex_unlock(&mutex1);  
  22.  
  23.    return sequence1;  
  24. }  
  25.  
  26. int func2()  
  27. {  
  28.    pthread_mutex_lock(&mutex2);  
  29.    ++sequence2;  
  30.    sleep(1);  
  31.    pthread_mutex_lock(&mutex1);  
  32.    ++sequence1;  
  33.    pthread_mutex_unlock(&mutex1);  
  34.    pthread_mutex_unlock(&mutex2);  
  35.  
  36.    return sequence2;  
  37. }  
  38.  
  39. void* thread1(void* arg)  
  40. {  
  41.    while (1)  
  42.    {  
  43.        int iRetValue = func1();  
  44.  
  45.        if (iRetValue == 100000)  
  46.        {  
  47.            pthread_exit(NULL);  
  48.        }  
  49.    }  
  50. }  
  51.  
  52. void* thread2(void* arg)  
  53. {  
  54.    while (1)  
  55.    {  
  56.        int iRetValue = func2();  
  57.  
  58.        if (iRetValue == 100000)  
  59.        {  
  60.            pthread_exit(NULL);  
  61.        }  
  62.    }  
  63. }  
  64.  
  65. void* thread3(void* arg)  
  66. {  
  67.    while (1)  
  68.    {  
  69.        sleep(1);  
  70.        char szBuf[128];  
  71.        memset(szBuf, 0, sizeof(szBuf));  
  72.        strcpy(szBuf, "thread3");  
  73.    }  
  74. }  
  75.  
  76. void* thread4(void* arg)  
  77. {  
  78.    while (1)  
  79.    {  
  80.        sleep(1);  
  81.        char szBuf[128];  
  82.        memset(szBuf, 0, sizeof(szBuf));  
  83.        strcpy(szBuf, "thread3");  
  84.    }  
  85. }  
  86.  
  87. int main()  
  88. {  
  89.    pthread_t tid[4];  
  90.    if (pthread_create(&tid[0], NULL, &thread1, NULL) != 0)  
  91.    {  
  92.        _exit(1);  
  93.    }  
  94.    if (pthread_create(&tid[1], NULL, &thread2, NULL) != 0)  
  95.    {  
  96.        _exit(1);  
  97.    }  
  98.    if (pthread_create(&tid[2], NULL, &thread3, NULL) != 0)  
  99.    {  
  100.        _exit(1);  
  101.    }  
  102.    if (pthread_create(&tid[3], NULL, &thread4, NULL) != 0)  
  103.    {  
  104.        _exit(1);  
  105.    }  
  106.  
  107.    sleep(5);  
  108.    //pthread_cancel(tid[0]);  
  109.  
  110.    pthread_join(tid[0], NULL);  
  111.    pthread_join(tid[1], NULL);  
  112.    pthread_join(tid[2], NULL);  
  113.    pthread_join(tid[3], NULL);  
  114.  
  115.    pthread_mutex_destroy(&mutex1);  
  116.    pthread_mutex_destroy(&mutex2);  
  117.    pthread_mutex_destroy(&mutex3);  
  118.    pthread_mutex_destroy(&mutex4);  
  119.  
  120.    return 0;  
  121.  

清單 2. 編譯測試程序

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

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

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

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

  1. [dyu@xilinuxbldsrv purify]$ pstack 6721  
  2.  Thread 5 (Thread 0x41e37940 (LWP 6722)):  
  3.  #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0  
  4.  #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0  
  5.  #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0  
  6.  #3  0x0000000000400a9b in func1() ()  
  7.  #4  0x0000000000400ad7 in thread1(void*) ()  
  8.  #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0  
  9.  #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6  
  10.  Thread 4 (Thread 0x42838940 (LWP 6723)):  
  11.  #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0  
  12.  #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0  
  13.  #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0  
  14.  #3  0x0000000000400a17 in func2() ()  
  15.  #4  0x0000000000400a53 in thread2(void*) ()  
  16.  #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0  
  17.  #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6  
  18.  Thread 3 (Thread 0x43239940 (LWP 6724)):  
  19.  #0  0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6  
  20.  #1  0x0000003d19c9a364 in sleep () from /lib64/libc.so.6  
  21.  #2  0x00000000004009bc in thread3(void*) ()  
  22.  #3  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0  
  23.  #4  0x0000003d19cd40cd in clone () from /lib64/libc.so.6  
  24.  Thread 2 (Thread 0x43c3a940 (LWP 6725)):  
  25.  #0  0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6  
  26.  #1  0x0000003d19c9a364 in sleep () from /lib64/libc.so.6  
  27.  #2  0x0000000000400976 in thread4(void*) ()  
  28.  #3  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0  
  29.  #4  0x0000003d19cd40cd in clone () from /lib64/libc.so.6  
  30.  Thread 1 (Thread 0x2b984ecabd90 (LWP 6721)):  
  31.  #0  0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0  
  32.  #1  0x0000000000400900 in main ()  

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

  1. [dyu@xilinuxbldsrv purify]$ pstack 6721  
  2. Thread 5 (Thread 0x40bd6940 (LWP 6722)):  
  3. #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0  
  4. #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0  
  5. #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0  
  6. #3  0x0000000000400a87 in func1() ()  
  7. #4  0x0000000000400ac3 in thread1(void*) ()  
  8. #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0  
  9. #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6  
  10. Thread 4 (Thread 0x415d7940 (LWP 6723)):  
  11. #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0  
  12. #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0  
  13. #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0  
  14. #3  0x0000000000400a03 in func2() ()  
  15. #4  0x0000000000400a3f in thread2(void*) ()  
  16. #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0  
  17. #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6  
  18. Thread 3 (Thread 0x41fd8940 (LWP 6724)):  
  19. #0  0x0000003d19c7aec2 in memset () from /lib64/libc.so.6  
  20. #1  0x00000000004009be in thread3(void*) ()  
  21. #2  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0  
  22. #3  0x0000003d19cd40cd in clone () from /lib64/libc.so.6  
  23. Thread 2 (Thread 0x429d9940 (LWP 6725)):  
  24. #0  0x0000003d19c7ae0d in memset () from /lib64/libc.so.6  
  25. #1  0x0000000000400982 in thread4(void*) ()  
  26. #2  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0  
  27. #3  0x0000003d19cd40cd in clone () from /lib64/libc.so.6  
  28. Thread 1 (Thread 0x2af906fd9d90 (LWP 6721)):  
  29. #0  0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0  
  30. #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 到死鎖進程

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

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

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

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

  1. (gdb) f 3  
  2.  #3  0x0000000000400a9b in func1 () at lock.cpp:18  
  3.  18          pthread_mutex_lock(&mutex2);  
  4.  (gdb) thread 4  
  5.  [Switching to thread 4 (Thread 0x42838940 (LWP 6723))]#0  0x0000003d1a80d4c4 in  
  6.  __lll_lock_wait () from /lib64/libpthread.so.0  
  7.  (gdb) f 3  
  8.  #3  0x0000000000400a17 in func2 () at lock.cpp:31  
  9.  31          pthread_mutex_lock(&mutex1);  
  10.  (gdb) p mutex1  
  11.  $1 = {__data = {__lock = 2, __count = 0, __owner = 6722, __nusers = 1, __kind = 0,  
  12.  __spins = 0, __list = {__prev = 0x0, __next = 0x0}},  
  13.   __size = "\002\000\000\000\000\000\000\000B\032\000\000\001"'\000' 
  14.  <repeats 26 times>, __align = 2}  
  15.  (gdb) p mutex3  
  16.  $2 = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0,  
  17.  __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}},  
  18.  __size = '\000' <repeats 39 times>, __align = 0}  
  19.  (gdb) p mutex2  
  20.  $3 = {__data = {__lock = 2, __count = 0, __owner = 6723, __nusers = 1,  
  21.  __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}},  
  22.   __size = "\002\000\000\000\000\000\000\000C\032\000\000\001"'\000' 
  23.  <repeats 26 times>, __align = 2}  
  24.  (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 平臺下分析死鎖問題的方法,對一些死鎖問題的分析有一定作用。希望對大家有幫助。理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以***可能地避免、預防和解除死鎖。所以,在系統設計、進程調度等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配算法,避免進程***占據系統資源。此外,也要防止進程在處于等待狀態的情況下占用資源 , 在系統運行過程中,對進程發出的每一個系統能夠滿足的資源申請進行動態檢查,并根據檢查結果決定是否分配資源,若分配后系統可能發生死鎖,則不予分配,否則予以分配。因此,對資源的分配要給予合理的規劃,使用有序資源分配法和銀行家算法等是避免死鎖的有效方法。 

責任編輯:龐桂玉 來源: 嵌入式Linux中文站
相關推薦

2012-08-13 10:16:34

IBMdW

2021-04-09 10:58:51

UbuntuLinuxWindows 10

2010-03-15 14:10:34

ubuntu系統

2023-07-11 09:24:11

2019-07-05 09:45:19

UbuntuLinux釋放空間

2017-07-17 10:53:06

Linux交換分區

2010-03-03 13:56:43

Linux ubant

2010-08-27 10:40:58

Linux DHCP服

2018-01-15 14:36:34

Linux負載CPU

2010-03-10 15:33:31

Linux誤刪除

2009-08-08 09:50:30

Linux操作系統共享內存Linux

2010-08-06 13:23:58

NFS配置

2010-07-20 14:07:31

更改TELNET端口

2010-06-08 17:46:31

OpenSUSE安裝

2021-11-02 22:46:01

Windows 11Windows微軟

2019-12-24 11:16:09

Windows 10Windows任務欄

2010-09-30 14:01:38

2010-11-23 16:21:07

MySQL大表備份

2009-08-12 16:47:36

C#轉換農歷

2010-05-14 16:41:58

MySQL鏡像數據庫
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩精品一区二区三区在线播放 | 日本一区二区三区四区 | 99re| 亚洲网站在线观看 | 久草视频在 | 国产综合精品一区二区三区 | 日日干夜夜操 | 精品久久久久久一区二区 | 日韩精品一区中文字幕 | 中文字幕一区二区三 | 国产成人在线视频免费观看 | 国产精品一区二区三区在线 | 亚洲精品在线视频 | 美女午夜影院 | 色综合久久久 | 韩三级在线观看 | 伊人久操| av电影一区| 毛片黄 | 开操网 | 欧美一极视频 | 永久av | 羞羞的视频免费看 | 欧美日韩免费视频 | 蜜桃视频成人 | 精品视频一区在线 | 午夜成人在线视频 | 国产一区二区三区视频在线观看 | 成人免费小视频 | 国产免费麻豆视频 | 亚洲欧美国产精品久久 | 九七午夜剧场福利写真 | 成年人免费网站 | 91一区二区 | 日本黄色免费大片 | 欧美亚洲视频在线观看 | 国产性色视频 | 日韩欧美国产一区二区三区 | 欧美jizzhd精品欧美巨大免费 | 中文字幕在线第一页 | 亚洲精品在线国产 |