青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

elva

GDB(GNU 項目調試器)

GDB(GNU 項目調試器)可以讓您了解程序在執行時“內部” 究竟在干些什么,以及在程序發生崩潰的瞬間正在做什么。
GDB 做以下 4 件主要的事情來幫助您捕獲程序中的 bug:
l
在程序啟動之前指定一些可以影響程序行為的變量或條件
l
在某個指定的地方或條件下暫停程序
l
在程序停止時檢查已經發生了什么
l
在程序執行過程中修改程序中的變量或條件,這樣就可以體驗修復一個 bug 的成果,并繼續了解其他 bug

要調試的程序可以是使用 C、C++、Pascal、Objective-C 以及其他很多語言編寫的。GDB 的二進制文件名是 gdb。
gdb 中有很多命令。使用help命令可以列出所有的命令,以及關于如何使用這些命令的介紹。下表給出了最常用的 GDB 命令。

表 1. gdb 中最常用的命令
命令
說明
例子
help
顯示命令類別
help- 顯示命令類別
help breakpoints- 顯示屬于 breakpoints 類別的命令
help break- 顯示 break 命令的解釋
run
啟動所調試的程序
?
kill
終止正在調試的程序的執行
通常這會在要執行的代碼行已經超過了您想要調試的代碼時使用。執行kill會重置斷點,并從頭再次運行這個程序



cont
所調試的程序運行到一個斷點、異常或單步之后,繼續執行
?
info break
顯示當前的斷點或觀察點
?
break
在指定的行或函數處設置斷點
break 93 if i=8- 當變量 i 等于 8 時,在第 93 行停止程序執行
Step
單步執行程序,直到它到達一個不同的源代碼行。您可以使用s來代表 step 命令
?
Next
與 step 命令類似,只是它不會“單步跟蹤到”子例程中
?
print
打印一個變量或表達式的值
print pointer- 打印變量指針的內容
print *pointer- 打印指針所指向的數據結構的內容
delete
刪除某些斷點或自動顯示表達式
delete 1- 刪除斷點 1。斷點可以通過info break來顯示
watch
為一個表達式設置一個觀察點。當表達式的值發生變化時,這個觀察點就會暫停程序的執行
?
where
打印所有堆棧幀的棧信息
where- 不使用參數,輸出當前線程的堆棧信息
where all- 輸出當前線程組中所有線程的堆棧信息
where threadindex- 輸出指定線程的堆棧信息
attach
開始查看一個已經運行的進程
attach - 附加到進程 process_id 上。process_id 可以使用 ps 命令找到
info thread
顯示當前正在運行的線程
?
thread apply threadno command
對一個線程運行 gdb 命令
thread apply 3 where- 對線程 3 運行where命令
Thread threadno
選擇一個線程作為當前線程
?
如果一個程序崩潰了,并生成了一個 core 文件,您可以查看 core 文件來判斷進程結束時的狀態。使用下面的命令啟動 gdb:
# gdb programname corefilename
要調試一個 core 文件,您需要可執行程序、源代碼文件以及 core 文件。要對一個 core 文件啟動 gdb,請使用 -c 選項:
# gdb -c core programname
gdb 會顯示是哪行代碼導致這個程序產生了核心轉儲。
默認情況下,核心轉儲在 Novell 的 SUSE LINUX Enterprise Server 9(SLES 9)和 Red Hat? Enterprise Linux Advanced Server(RHEL AS 4)上都是禁用的。要啟用核心轉儲,請以 root 用戶的身份在命令行中執行ulimit –c unlimited。
清單 8中的例子闡述了如何使用 gdb 來定位程序中的 bug。清單 8 是一段包含 bug 的 C++ 代碼。
清單 8中的 C++ 程序試圖構建 10 個鏈接在一起的數字框(number box),例如:

圖 1. 一個包含 10 個鏈接在一起的數字框的列表

然后試圖從這個列表中逐個刪除數字框。
編譯并運行這個程序,如下所示:

清單 9. 編譯并運行這個程序
# g++ -g -o gdbtest1 gdbtest1.cpp
# ./gdbtest1
Number Box "0" created
Number Box "1" created
Number Box "2" created
Number Box "3" created
Number Box "4" created
Number Box "5" created
Number Box "6" created
Number Box "7" created
Number Box "8" created
Number Box "9" created
list created
Number Box "9" deleted
Segmentation fault
正如您可以看到的一樣,這個程序會導致段錯誤。調用 gdb 來看一下這個問題,如下所示:

清單 10. 調用 gdb
# gdb ./gdbtest1
GNU gdb 6.2.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.
Type "show warranty" for
details.
This GDB was configured as "ppc-suse-linux"...Using host libthread_db
library "/lib/tls/libthread_db.so.1".
(gdb)
您知道段錯誤是在數字框 "9" 被刪除之后發生的。執行run和where命令來精確定位段錯誤發生在程序中的什么位置。

清單 11. 執行 run 和 where 命令
(gdb) run
Starting program: /root/test/gdbtest1
Number Box "0" created
Number Box "1" created
Number Box "2" created
Number Box "3" created
Number Box "4" created
Number Box "5" created
Number Box "6" created
Number Box "7" created
Number Box "8" created
Number Box "9" created
list created
Number Box "9" deleted
Program received signal SIGSEGV, Segmentation fault.
0x10000f74 in NumBox::GetNext (this=0x0) at gdbtest1.cpp:14
14
NumBox*GetNext() const { return Next; }
(gdb) where
#0
0x10000f74 in NumBox::GetNext (this=0x0) at gdbtest1.cpp:14
#1
0x10000d10 in NumChain::RemoveBox (this=0x10012008,
item_to_remove=@0xffffe200) at gdbtest1.cpp:63
#2
0x10000978 in main (argc=1, argv=0xffffe554) at gdbtest1.cpp:94
(gdb)
跟蹤信息顯示這個程序在第 14 行NumBox::GetNext (this=0x0)接收到一個段錯誤。這個數字框上 Next 指針的地址是 0x0,這對于一個數字框來說是一個無效的地址。從上面的跟蹤信息可以看出,GetNext函數是由 63 行調用的。看一下在 gdbtest1.cpp 的 63 行附近發生了什么:

清單 12. gdbtest1.cpp
54
} else {

55
temp->SetNext (current->GetNext());

56
delete temp;

57

temp = 0;

58
return 0;

59
}

60
}

61
current = 0;

62
temp = current;

63
current = current->GetNext();

64
}

65

66
return -1;
第 61 行current=0將這個指針設置為一個無效的地址,這正是產生段錯誤的根源。注釋掉第 61 行,將其保存為 gdbtest2.cpp,然后編譯并重新運行。

清單 13. 再次運行程序(gdbtest2.cpp)
# g++ -g -o gdbtest2 gdbtest2.cpp
# ./gdbtest2
Number Box "0" created
Number Box "1" created
Number Box "2" created
Number Box "3" created
Number Box "4" created
Number Box "5" created
Number Box "6" created
Number Box "7" created
Number Box "8" created
Number Box "9" created
list created
Number Box "9" deleted
Number Box "0" deleted
這個程序現在可以成功完成而不會出現段錯誤了。然而,結果并不像我們預期的一樣:程序在刪除 Number Box "9"之后刪除了 Number Box "0",而不像我們期望的一樣刪除 Number Box "8,"。使用 gdb 再次來看一下。

清單 14. 再次使用 gdb 進行查看
# gdb ./gdbtest2
GNU gdb 6.2.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.
Type "show warranty" for
details.
This GDB was configured as "ppc-suse-linux"...Using host libthread_db
library "/lib/tls/libthread_db.so.1".
(gdb) break 94 if i==8
Breakpoint 1 at 0x10000968: file gdbtest2.cpp, line 94.
(gdb) run
Starting program: /root/test/gdbtest2
Number Box "0" created
Number Box "1" created
Number Box "2" created
Number Box "3" created
Number Box "4" created
Number Box "5" created
Number Box "6" created
Number Box "7" created
Number Box "8" created
Number Box "9" created
list created
Number Box "9" deleted
Breakpoint 1, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:94
94
list ->RemoveBox(i);
您可能希望找出為什么這個程序刪除的是 Number Box 0,而不是 Number Box 8,因此需要在您認為程序會刪除 Number Box 8 的地方停止程序。設置這個斷點:break 94 if i==8,可以在 i 等于 8 時在第 94 行處停止程序。然后單步跟蹤到RemoveBox()函數中。

清單 15. 單步跟蹤到 RemoveBox() 函數中
(gdb) s
38
NumBox *temp = 0;

(gdb) s
40
while (current != 0) {
(gdb) print pointer
$1 = (NumBox *) 0x100120a8

(gdb) print *pointer
$2 = {Num = 0, Next = 0x0}
(gdb)
指針早已指向了 Number Box "0",因此這個 bug 可能就存在于程序刪除 Number Box "9" 的地方。要在 gdb 中重新啟動這個程序,請使用kill刪除原來的斷點,然后添加一個 i 等于 9 時的新斷點,然后再次運行這個程序。

清單 16. 在 gdb 中重新啟動程序
(gdb) kill
Kill the program being debugged? (y or n) y
(gdb) info break
Num Type
Disp Enb Address
What
1
breakpoint
keep y
0x10000968 in main at gdbtest2.cpp:94

stop only if i == 8

breakpoint already hit 1 time
(gdb) delete 1
(gdb) break 94 if i==9
Breakpoint 2 at 0x10000968: file gdbtest2.cpp, line 94.
(gdb) run
Starting program: /root/test/gdbtest2
Number Box "0" created
Number Box "1" created
Number Box "2" created
Number Box "3" created
Number Box "4" created
Number Box "5" created
Number Box "6" created
Number Box "7" created
Number Box "8" created
Number Box "9" created
list created
Breakpoint 2, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:94
94
list ->RemoveBox(i);
(gdb)
當這一次單步跟蹤RemoveBox()函數時,要特別注意list->pointer正在指向哪一個數字框,因為 bug 可能就在于list->pointer開始指向 Number Box "0" 的地方。請使用display *pointer命令來查看,這會自動顯示這個函數。

清單 17. 使用 display *pointer 命令進行監視
Breakpoint 2, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:94
94
list ->RemoveBox(i);
(gdb) s
NumChain::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)
at gdbtest2.cpp:37
37
NumBox *current = pointer;
(gdb) display *pointer
1: *this->pointer = {Num = 9, Next = 0x10012098}
(gdb) s
38
NumBox *temp = 0;

1: *this->pointer = {Num = 9, Next = 0x10012098}
(gdb) s
40
while (current != 0) {
1: *this->pointer = {Num = 9, Next = 0x10012098}
(gdb) s
41
if (current->GetValue() == item_to_remove) {
1: *this->pointer = {Num = 9, Next = 0x10012098}
(gdb) s
NumBox::GetValue (this=0x100120a8) at gdbtest2.cpp:16
16
const T& GetValue () const { return Num; }
(gdb) s
NumChain::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)
at gdbtest2.cpp:42
42
if (temp == 0) {
1: *this->pointer = {Num = 9, Next = 0x10012098}
(gdb) s
44
if (current->GetNext() == 0) {
1: *this->pointer = {Num = 9, Next = 0x10012098}
(gdb) s
NumBox::GetNext (this=0x100120a8) at gdbtest2.cpp:14
14
NumBox*GetNext() const { return Next; }
(gdb) s
NumChain::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)
at gdbtest2.cpp:50
50
delete current;
1: *this->pointer = {Num = 9, Next = 0x10012098}
(gdb) s
~NumBox (this=0x100120a8) at gdbtest2.cpp:10
10
std::cout << "Number Box " <<"\""
<< GetValue()
<<"\""
<<" deleted" << std::endl;
(gdb) s
NumBox::GetValue (this=0x100120a8) at gdbtest2.cpp:16
16
const T& GetValue () const { return Num; }
(gdb) s
Number Box "9" deleted
~NumBox (this=0x100120a8) at gdbtest2.cpp:11
11
Next = 0;
(gdb) s
NumChain::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)
at gdbtest2.cpp:51
51
current = 0;
1: *this->pointer = {Num = 0, Next = 0x0}
(gdb) s
53
return 0;
1: *this->pointer = {Num = 0, Next = 0x0}
(gdb) s
0x10000d1c
66
return -1;
1: *this->pointer = {Num = 0, Next = 0x0}
從上面的跟蹤過程中,您可以看到list->pointer在刪除 Number Box "9" 之后指向了 Number Box "0"。這個邏輯并不正確,因為在刪除 Number Box "9" 之后,list->pointer應該指向的是 Number Box "8"。現在非常顯然我們應該在第 50 行之前添加一條語句pointer = pointer->GetNext();,如下所示:

清單 18. 在第 50 行之前添加一條 pointer = pointer->GetNext(); 語句
49
} else {

50
pointer = pointer->GetNext();

51
delete current;

52
current = 0;

53
}

54

return 0;
將新修改之后的程序保存為 gdbtest3.cpp,然后編譯并再次運行。

清單 19. 再次運行程序(gdbtest3.cpp)
# g++ -g -o gdbtest3 gdbtest3.cpp
# ./gdbtest3
Number Box "0" created
Number Box "1" created
Number Box "2" created
Number Box "3" created
Number Box "4" created
Number Box "5" created
Number Box "6" created
Number Box "7" created
Number Box "8" created
Number Box "9" created
list created
Number Box "9" deleted
Number Box "8" deleted
Number Box "7" deleted
Number Box "6" deleted
Number Box "5" deleted
Number Box "4" deleted
Number Box "3" deleted
Number Box "2" deleted
Number Box "1" deleted
Number Box "0" deleted
這才是我們期望的結果。
多線程環境
在 GDB 中有一些特殊的命令可以用于多線程應用程序的調試。下面這個例子給出了一個死鎖情況,并介紹了如何使用這些命令來檢查多線程應用程序中的問題:

清單 20. 多線程的例子
#include
#include "pthread.h>
pthread_mutex_t AccountA_mutex;
pthread_mutex_t AccountB_mutex;
struct BankAccount {

char account_name[1];

int balance;
};
struct BankAccount
accountA = {"A", 10000 };
struct BankAccount
accountB = {"B", 20000 };
void * transferAB (void* amount_ptr) {

int amount = *((int*)amount_ptr);

pthread_mutex_lock(&AccountA_mutex);

if (accountA.balance < amount)
{

printf("There is not enough memory in Account A!\n");

pthread_mutex_unlock(&AccountA_mutex);


pthread_exit((void *)1);

}

accountA.balance -=amount;

sleep(1);

pthread_mutex_lock(&AccountB_mutex);

accountB.balance +=amount;

pthread_mutex_unlock(&AccountA_mutex);

pthread_mutex_unlock(&AccountB_mutex);
}
void * transferBA (void* amount_ptr) {

int amount = *((int*)amount_ptr);

pthread_mutex_lock(&AccountB_mutex);

if (accountB.balance < amount)
{

printf("There is not enough memory in Account B!\n");

pthread_mutex_unlock(&AccountB_mutex);

pthread_exit((void *)1);

}

accountB.balance -=amount;

sleep(1);

pthread_mutex_lock(&AccountA_mutex);

accountA.balance +=amount;

pthread_mutex_unlock(&AccountB_mutex);

pthread_mutex_unlock(&AccountA_mutex);
}
int main(int argc, char* argv[]) {

int
threadid[4];

pthread_t
pthread[4];

int
transfer_amount[4] = {100, 200, 300, 400};

int
final_balanceA, final_balanceB;

final_balanceA=accountA.balance-transfer_amount[0]-
transfer_amount[1]+transfer_amount[2]+transfer_amount[3];

final_balanceB=accountB.balance+transfer_amount[0]
+transfer_amount[1]-transfer_amount[2]-transfer_amount[3];

if (threadid[0] = pthread_create(&pthread[0], NULL, transferAB,
(void*)&transfer_amount[0]) " 0) {

perror("Thread #0 creation failed.");

exit (1);

}

if (threadid[1] = pthread_create(&pthread[1], NULL, transferAB,
(void*)&transfer_amount[1]) " 0) {

perror("Thread #1 creation failed.");

exit (1);

}

if (threadid[2] = pthread_create(&pthread[2], NULL, transferBA,
(void*)&transfer_amount[2]) < 0) {

perror("Thread #2 creation failed.");

exit (1);

}

if (threadid[3] = pthread_create(&pthread[3], NULL, transferBA,
(void*)&transfer_amount[3]) < 0) {

perror("Thread #3 creation failed.");

exit (1);

}

printf("Transitions are in progress..");

while ((accountA.balance != final_balanceA) && (accountB.balance
!= final_balanceB)) {

printf("..");

}

printf("\nAll the
money is transferred !!\n");
}
使用 gcc 來編譯這個程序,如下所示:
# gcc -g -o gdbtest2 gdbtest2.c -L/lib/tls -lpthread
程序 gdbtest2 會掛起,不會返回一條All the money is transferred !!消息。
將 gdb 附加到正在運行的進程上,從而了解這個進程內部正在發生什么。

清單 21. 將 gdb 附加到正在運行的進程上
# ps -ef |grep gdbtest2
root
9510
8065
1 06:30 pts/1
00:00:00 ./gdbtest2
root
9516
9400
0 06:30 pts/4
00:00:00 grep gdbtest2
# gdb -pid 9510
GNU gdb 6.2.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.
Type "show warranty" for
details.
This GDB was configured as "ppc-suse-linux".
Attaching to process 9510
Reading symbols from /root/test/gdbtest2...done.
Using host libthread_db library "/lib/tls/libthread_db.so.1".
Reading symbols from /lib/tls/libpthread.so.0...done.
[Thread debugging using libthread_db enabled]
[New Thread 1073991712 (LWP 9510)]
[New Thread 1090771744 (LWP 9514)]
[New Thread 1086577440 (LWP 9513)]
[New Thread 1082383136 (LWP 9512)]
[New Thread 1078188832 (LWP 9511)]
Loaded symbols for /lib/tls/libpthread.so.0
Reading symbols from /lib/tls/libc.so.6...done.
Loaded symbols for /lib/tls/libc.so.6
Reading symbols from /lib/ld.so.1...done.
Loaded symbols for /lib/ld.so.1
0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
(gdb) info thread

5 Thread 1078188832 (LWP 9511)
0x0ffe94ec in __lll_lock_wait ()
from /lib/tls/libpthread.so.0

4 Thread 1082383136 (LWP 9512)
0x0ffe94ec in __lll_lock_wait ()
from /lib/tls/libpthread.so.0

3 Thread 1086577440 (LWP 9513)
0x0ffe94ec in __lll_lock_wait ()
from /lib/tls/libpthread.so.0

2 Thread 1090771744 (LWP 9514)
0x0ffe94ec in __lll_lock_wait ()
from /lib/tls/libpthread.so.0

1 Thread 1073991712 (LWP 9510)
0x0ff4ac40 in __write_nocancel ()
from /lib/tls/libc.so.6
(gdb)
從info thread命令中,我們可以了解到除了主線程(thread #1)之外的所有線程都在等待函數__lll_lock_wait ()完成。
使用thread apply threadno where命令來查看每個線程到底運行到了什么地方:

清單 22. 查看每個線程運行到了什么地方
(gdb) thread apply 1 where
Thread 1 (Thread 1073991712 (LWP 9510)):
#0
0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
#1
0x0ff4ac28 in __write_nocancel () from /lib/tls/libc.so.6
Previous frame. identical to this frame. (corrupt stack?)
#0
0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
(gdb) thread apply 2 where
Thread 2 (Thread 1090771744 (LWP 9514)):
#0
0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0
#1
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#2
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#3
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#4
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
Previous frame. inner to this frame. (corrupt stack?)
#0
0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
(gdb) thread apply 3 where
Thread 3 (Thread 1086577440 (LWP 9513)):
#0
0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0
#1
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#2
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#3
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#4
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
Previous frame. inner to this frame. (corrupt stack?)
#0
0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
(gdb) thread apply 4 where
Thread 4 (Thread 1082383136 (LWP 9512)):
#0
0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0
#1
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#2
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#3
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#4
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
Previous frame. inner to this frame. (corrupt stack?)
#0
0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6

(gdb) thread apply 5 where
Thread 5 (Thread 1078188832 (LWP 9511)):
#0
0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0
#1
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#2
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#3
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
#4
0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
Previous frame. inner to this frame. (corrupt stack?)
#0
0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
每個線程都試圖對一個互斥體進行加鎖,但是這個互斥體卻是不可用的,可能是因為有另外一個線程已經對其進行加鎖了。從上面的證據我們可以判斷程序中一定存在死鎖。您還可以看到哪個線程現在擁有這個互斥體。

清單 23. 查看哪個線程擁有互斥體
(gdb) print AccountA_mutex
$1 = {__m_reserved = 2, __m_count = 0, __m_owner = 0x2527,
__m_kind = 0, __m_lock
= {__status = 1, __spinlock = 0}}
(gdb) print 0x2527
$2 = 9511
(gdb) print AccountB_mutex
$3 = {__m_reserved = 2, __m_count = 0, __m_owner = 0x2529,
__m_kind = 0, __m_lock = {__status = 1, __spinlock = 0}}
(gdb) print 0x2529
$4 = 9513
(gdb)
從上面的命令中,我們可以看出AccontA_mutex是被線程 5(LWP 9511)加鎖(擁有)的,而AccontB_mutex是被線程 3(LWP 9513)加鎖(擁有)的。
為了解決上面的死鎖情況,可以按照相同的順序對互斥體進行加鎖,如下所示:
清單 24. 按照相同的順序對互斥體進行加鎖
.
.
void * transferAB (void* amount_ptr) {

int amount = *((int*)amount_ptr);

pthread_mutex_lock(&AccountA_mutex);

pthread_mutex_lock(&AccountB_mutex);

if (accountA.balance < amount)
{

printf("There is not enough memory in Account A!\n");

pthread_mutex_unlock(&AccountA_mutex);

pthread_exit((void *)1);

}

accountA.balance -=amount;

sleep(1);

accountB.balance +=amount;

pthread_mutex_unlock(&AccountA_mutex);

pthread_mutex_unlock(&AccountB_mutex);
}
void * transferBA (void* amount_ptr) {

int amount = *((int*)amount_ptr);

pthread_mutex_lock(&AccountA_mutex);

pthread_mutex_lock(&AccountB_mutex);

if (accountB.balance < amount)
{

printf("There is not enough memory in Account B!\n");

pthread_mutex_unlock(&AccountB_mutex);

pthread_exit((void *)1);

}

accountB.balance -=amount;

sleep(1);

accountA.balance +=amount;

pthread_mutex_unlock(&AccountA_mutex);

pthread_mutex_unlock(&AccountB_mutex);
}
.
.
或者對每個帳號單獨進行加鎖,如下所示:
清單 25. 對每個帳號單獨進行加鎖
.
.
void * transferAB (void* amount_ptr) {

int amount = *((int*)amount_ptr);

pthread_mutex_lock(&AccountA_mutex);

if (accountA.balance < amount)
{

printf("There is not enough memory in Account A!\n");

pthread_mutex_unlock(&AccountA_mutex);

pthread_exit((void *)1);

}

accountA.balance -=amount;

sleep(1);

pthread_mutex_unlock(&AccountA_mutex);

pthread_mutex_lock(&AccountB_mutex);

accountB.balance +=amount;

pthread_mutex_unlock(&AccountB_mutex);
}
void * transferBA (void* amount_ptr) {

int amount = *((int*)amount_ptr);

pthread_mutex_lock(&AccountB_mutex);

if (accountB.balance < amount)
{

printf("There is not enough memory in Account B!\n");

pthread_mutex_unlock(&AccountB_mutex);

pthread_exit((void *)1);

}

accountB.balance -=amount;

sleep(1);

pthread_mutex_unlock(&AccountB_mutex);

pthread_mutex_lock(&AccountA_mutex);

accountA.balance +=amount;

pthread_mutex_unlock(&AccountA_mutex);
}
.
.
.

posted on 2010-08-05 18:05 葉子 閱讀(932) 評論(0)  編輯 收藏 引用 所屬分類: C\C++

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久久久久久久久码影片| 免费日本视频一区| 国内精品视频一区| 国产精品一区二区你懂得 | 免费观看日韩av| 欧美主播一区二区三区美女 久久精品人 | 亚洲午夜一区二区三区| 99国产精品久久久| 亚洲你懂的在线视频| 久久久久久噜噜噜久久久精品| 玖玖玖免费嫩草在线影院一区| 美女图片一区二区| 欧美精品三级| 国产精品一卡二卡| 在线免费观看视频一区| 中国成人亚色综合网站| 久久九九免费视频| 亚洲高清不卡在线观看| 亚洲高清资源| 亚洲精品美女久久久久| 亚洲校园激情| 亚洲夜间福利| 久久亚洲春色中文字幕| 欧美激情一区二区三区成人| 一区二区三区精品国产| 久久精品国产成人| 欧美国产精品日韩| 国内久久精品| avtt综合网| 久久亚洲一区二区三区四区| 亚洲精品在线一区二区| 午夜视频在线观看一区| 欧美激情导航| 狠狠做深爱婷婷久久综合一区| 亚洲精品一区二区三区樱花 | 激情久久久久久久| 中文精品在线| 欧美h视频在线| 亚洲色图在线视频| 欧美理论视频| 91久久久久久久久久久久久| 亚洲综合色丁香婷婷六月图片| 米奇777超碰欧美日韩亚洲| 在线视频你懂得一区二区三区| 久久夜色精品国产欧美乱极品 | 亚洲第一福利社区| 久久精品国产77777蜜臀| 一本色道久久综合亚洲精品高清| 久热精品视频在线观看一区| 国产美女精品一区二区三区| 99精品久久久| 91久久一区二区| 免费在线看一区| 在线精品一区| 麻豆成人小视频| 欧美在线黄色| 激情综合自拍| 免费亚洲婷婷| 蜜臀久久99精品久久久画质超高清 | 性色av一区二区怡红| 日韩视频精品| 欧美日韩免费在线观看| 日韩一级精品视频在线观看| 亚洲激情成人网| 欧美日韩免费观看一区| 亚洲无吗在线| 亚洲欧美久久| 国内精品久久久久伊人av| 久久久久亚洲综合| 久久久久九九九九| 在线成人激情黄色| 欧美第一黄色网| 欧美日韩国产精品专区| 欧美一区二区三区视频| 亚洲精品久久久一区二区三区| 欧美aaaaaaaa牛牛影院| 亚洲国产精品久久| 亚洲缚视频在线观看| 欧美激情一区二区三区在线| 日韩小视频在线观看专区| 亚洲精品孕妇| 国产精品美女久久福利网站| 久久精品国产精品| 午夜精品免费在线| 亚洲国产精品va| 99精品欧美一区二区蜜桃免费| 国产精品日韩一区二区三区| 久久影视精品| 欧美激情网站在线观看| 亚洲欧美日韩一区在线观看| 欧美亚洲一区二区三区| 亚洲黄色大片| 亚洲一区精品视频| 亚洲精品国产精品久久清纯直播| 亚洲精品美女在线观看播放| 国产视频欧美| 亚洲精品一级| 国产日韩一区| 亚洲精品日韩综合观看成人91| 国产日韩欧美成人| 亚洲人成网在线播放| 国产欧美成人| 日韩一区二区精品在线观看| 国产一区在线视频| 中文在线不卡视频| 亚洲精品久久久久久一区二区| 亚洲色在线视频| 亚洲激情网站免费观看| 午夜精品网站| 亚洲欧美日本精品| 免费国产一区二区| 久久精品人人爽| 国产精品v一区二区三区| 欧美成人精品在线播放| 国产一区二区中文字幕免费看| 9i看片成人免费高清| 亚洲美女在线观看| 久久中文精品| 美女主播精品视频一二三四| 国产欧美婷婷中文| 亚洲性图久久| 亚洲视频在线观看视频| 免费观看30秒视频久久| 久久久久久一区二区三区| 国产嫩草一区二区三区在线观看| 亚洲看片一区| 日韩视频免费观看高清在线视频 | 尤妮丝一区二区裸体视频| 一区二区三区不卡视频在线观看| 亚洲娇小video精品| 老妇喷水一区二区三区| 久久综合狠狠综合久久综青草| 国产精品一区在线观看你懂的| 一本色道久久综合一区| 亚洲免费网站| 国产精品影片在线观看| 亚洲五月六月| 极品尤物久久久av免费看| 亚洲欧美另类在线| 亚洲欧美日本视频在线观看| 欧美日韩亚洲综合| 亚洲精品影视在线观看| 一级成人国产| 欧美日韩久久精品| 国产精品99久久久久久久vr| 在线视频日本亚洲性| 欧美视频在线一区二区三区| 亚洲男人第一av网站| 久久久久成人网| 在线观看国产精品淫| 久久影院午夜论| 亚洲高清不卡一区| 一区二区三区导航| 国产精品久久久久永久免费观看 | 亚洲精品一区久久久久久| 噜噜噜噜噜久久久久久91| 亚洲福利精品| 亚洲一区二区三区四区在线观看 | 亚洲日本中文| 欧美私人网站| 久久精品理论片| 亚洲国产三级在线| 亚洲在线一区二区三区| 国产主播精品在线| 欧美不卡在线视频| 亚洲综合国产激情另类一区| 麻豆精品一区二区av白丝在线| 亚洲精品免费看| 国产欧美日韩一区二区三区在线观看| 久久久999精品免费| 亚洲免费久久| 美日韩在线观看| 一区二区三区视频在线播放| 国产精品尤物| 欧美成人精品激情在线观看| 亚洲午夜视频| 亚洲高清精品中出| 亚洲欧美日韩在线播放| 亚洲国产成人在线| 国产精品久久久久久久久久久久久久 | 国产日产高清欧美一区二区三区| 久久亚洲一区二区| 99综合在线| 亚洲国产高清视频| 久久久www成人免费毛片麻豆| 日韩午夜在线视频| 亚洲大片免费看| 国产一区二区三区四区老人 | 亚洲欧洲精品一区二区三区波多野1战4 | 欧美高清视频一区二区三区在线观看 | 午夜日本精品| 91久久国产自产拍夜夜嗨| 久久久xxx| 欧美一区国产一区| 亚洲视频一区在线| 日韩视频一区二区三区在线播放| 国产一区二区三区黄| 国产精品久久久久久av下载红粉| 欧美激情1区| 欧美91精品|