真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Linux上怎么做死鎖

本篇內(nèi)容主要講解“Linux上怎么做死鎖”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Linux上怎么做死鎖”吧!

為藍(lán)山等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及藍(lán)山網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站設(shè)計、成都做網(wǎng)站、藍(lán)山網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!

簡介

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

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

產(chǎn)生死鎖的四個必要條件

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

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

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

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

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

Linux上怎么做死鎖

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

使用 pstack 和 gdb 工具對死鎖程序進(jìn)行分析

pstack 在 Linux 平臺上的簡單介紹

pstack 是 Linux(比如 Red Hat Linux 系統(tǒng)、Ubuntu Linux  系統(tǒng)等)下一個很有用的工具,它的功能是打印輸出此進(jìn)程的堆棧信息??梢暂敵鏊芯€程的調(diào)用關(guān)系棧。

gdb 在 Linux 平臺上的簡單介紹

GDB 是 GNU 開源組織發(fā)布的一個強(qiáng)大的 UNIX 下的程序調(diào)試工具。Linux 系統(tǒng)中包含了 GNU 調(diào)試程序 gdb,它是一個用來調(diào)試 C 和  C++ 程序的調(diào)試器??梢允钩绦蜷_發(fā)者在程序運行時觀察程序的內(nèi)部結(jié)構(gòu)和內(nèi)存的使用情況 .

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

1 運行程序,設(shè)置能影響程序運行的參數(shù)和環(huán)境 ;

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

3 當(dāng)程序停止時,可以檢查程序的狀態(tài);

4 當(dāng)程序 crash 時,可以檢查 core 文件;

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

6 可以動態(tài)監(jiān)視程序中變量的值;

7 可以單步執(zhí)行代碼,觀察程序的運行狀態(tài)。

gdb 程序調(diào)試的對象是可執(zhí)行文件或者進(jìn)程,而不是程序的源代碼文件。然而,并不是所有的可執(zhí)行文件都可以用 gdb  調(diào)試。如果要讓產(chǎn)生的可執(zhí)行文件可以用來調(diào)試,需在執(zhí)行 g++(gcc)指令編譯程序時,加上 -g  參數(shù),指定程序在編譯時包含調(diào)試信息。調(diào)試信息包含程序里的每個變量的類型和在可執(zhí)行文件里的地址映射以及源代碼的行號。gdb  利用這些信息使源代碼和機(jī)器碼相關(guān)聯(lián)。gdb 的基本命令較多,不做詳細(xì)介紹,大家如果需要進(jìn)一步了解,請參見 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. 查找測試程序的進(jìn)程號

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

清單 4. 對死鎖進(jìn)程***次執(zhí)行 pstack(pstack –進(jìn)程號)的輸出結(jié)果

[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. 對死鎖進(jìn)程第二次執(zhí)行 pstack(pstack –進(jìn)程號)的輸出結(jié)果

[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 ()

連續(xù)多次查看這個進(jìn)程的函數(shù)調(diào)用關(guān)系堆棧進(jìn)行分析:當(dāng)進(jìn)程吊死時,多次使用 pstack  查看進(jìn)程的函數(shù)調(diào)用堆棧,死鎖線程將一直處于等鎖的狀態(tài),對比多次的函數(shù)調(diào)用堆棧輸出結(jié)果,確定哪兩個線程(或者幾個線程)一直沒有變化且一直處于等鎖的狀態(tài)(可能存在兩個線程  一直沒有變化)。

輸出分析:

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

Gdb into thread輸出:

清單 6. 然后通過 gdb attach 到死鎖進(jìn)程

(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)

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

到此,相信大家對“Linux上怎么做死鎖”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!


本文題目:Linux上怎么做死鎖
分享路徑:http://weahome.cn/article/jehoid.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部