久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Linux上怎么做死鎖

共計(jì) 9582 個(gè)字符,預(yù)計(jì)需要花費(fèi) 24 分鐘才能閱讀完成。

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

簡(jiǎn)介

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

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

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

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

(2) 請(qǐng)求與保持條件:一個(gè)進(jìn)程 (線(xiàn)程) 因請(qǐng)求資源而阻塞時(shí),對(duì)已獲得的資源保持不放。

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

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

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

注釋?zhuān)涸趫?zhí)行 func2 和 func4 之后,子線(xiàn)程 1 獲得了鎖 A,正試圖獲得鎖 B,但是子線(xiàn)程 2 此時(shí)獲得了鎖 B,正試圖獲得鎖 A,所以子線(xiàn)程  1 和子線(xiàn)程 2 將沒(méi)有辦法得到鎖 A 和鎖 B,因?yàn)樗鼈兏髯员粚?duì)方占有,永遠(yuǎn)不會(huì)釋放,所以發(fā)生了死鎖的現(xiàn)象。

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

pstack 在 Linux 平臺(tái)上的簡(jiǎn)單介紹

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

gdb 在 Linux 平臺(tái)上的簡(jiǎn)單介紹

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

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

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

2 控制程序在指定的條件下停止運(yùn)行;

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

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

5 可以修改程序的錯(cuò)誤,并重新運(yùn)行程序;

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

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

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

清單 1. 測(cè)試程序

#include  unistd.h  #include  pthread.h  #include  string.h  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. 編譯測(cè)試程序

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

清單 3. 查找測(cè)試程序的進(jìn)程號(hào)

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

清單 4. 對(duì)死鎖進(jìn)程 *** 次執(zhí)行 pstack(pstack ndash; 進(jìn)程號(hào))的輸出結(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. 對(duì)死鎖進(jìn)程第二次執(zhí)行 pstack(pstack ndash; 進(jìn)程號(hào))的輸出結(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ù)多次查看這個(gè)進(jìn)程的函數(shù)調(diào)用關(guān)系堆棧進(jìn)行分析:當(dāng)進(jìn)程吊死時(shí),多次使用 pstack   查看進(jìn)程的函數(shù)調(diào)用堆棧,死鎖線(xiàn)程將一直處于等鎖的狀態(tài),對(duì)比多次的函數(shù)調(diào)用堆棧輸出結(jié)果,確定哪兩個(gè)線(xiàn)程 (或者幾個(gè)線(xiàn)程) 一直沒(méi)有變化且一直處于等鎖的狀態(tài)(可能存在兩個(gè)線(xiàn)程   一直沒(méi)有變化)。

輸出分析:

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

Gdb into thread 輸出:

清單 6. 然后通過(guò) 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. 切換到線(xiàn)程 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. 線(xiàn)程 4 和線(xiàn)程 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   repeats 26 times , __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   repeats 39 times , __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   repeats 26 times , __align = 2} (gdb)

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

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

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-08-16發(fā)表,共計(jì)9582字。
轉(zhuǎn)載說(shuō)明:除特殊說(shuō)明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請(qǐng)注明出處。
評(píng)論(沒(méi)有評(píng)論)
主站蜘蛛池模板: 玉环县| 永昌县| 滨海县| 鲁山县| 隆安县| 突泉县| 南安市| 昌乐县| 黑山县| 彭阳县| 兰考县| 柘荣县| 略阳县| 正安县| 新沂市| 仪陇县| 白山市| 邓州市| 镇沅| 当涂县| 昆明市| 阳高县| 江阴市| 巨野县| 东源县| 泸西县| 亚东县| 沽源县| 沙河市| 邢台市| 九寨沟县| 甘泉县| 云阳县| 黄梅县| 松阳县| 商南县| 固始县| 师宗县| 南通市| 黄平县| 砀山县|