找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4825|回复: 0

GDB(GNU 项目调试器)

[复制链接]
发表于 2009-5-23 20:47:10 | 显示全部楼层 |阅读模式
GDBGNU 项目调试器)可以让您了解程序在执行时内部究竟在干些什么,以及在程序发生崩溃的瞬间正在做什么。
GDB 做以下 4 件主要的事情来帮助您捕获程序中的 bug
l
在程序启动之前指定一些可以影响程序行为的变量或条件
l
在某个指定的地方或条件下暂停程序
l
在程序停止时检查已经发生了什么
l
在程序执行过程中修改程序中的变量或条件,这样就可以体验修复一个 bug 的成果,并继续了解其他 bug

要调试的程序可以是使用 CC++PascalObjective-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 上。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 9SLES 9)和 Red Hat? Enterprise Linux Advanced ServerRHEL 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" 被删除之后发生的。执行runwhere命令来精确定位段错误发生在程序中的什么位置。

清单 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<int>::GetNext (this=0x0) at gdbtest1.cpp:14
14
NumBox<T>*GetNext() const { return Next; }

(gdb) where
#0
0x10000f74 in NumBox<int>::GetNext (this=0x0) at gdbtest1.cpp:14

#1
0x10000d10 in NumChain<int>::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<int>::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<T> *temp = 0;

(gdb) s
40
while (current != 0) {

(gdb) print pointer
$1 = (NumBox<int> *) 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<int>::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)
at gdbtest2.cpp:37

37
NumBox<T> *current = pointer;

(gdb) display *pointer
1: *this->pointer = {Num = 9, Next = 0x10012098}
(gdb) s
38
NumBox<T> *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<int>::GetValue (this=0x100120a8) at gdbtest2.cpp:16
16
const T& GetValue () const { return Num; }

(gdb) s
NumChain<int>::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<int>::GetNext (this=0x100120a8) at gdbtest2.cpp:14
14
NumBox<T>*GetNext() const { return Next; }

(gdb) s
NumChain<int>::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<int>::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<int>::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 <stdio.h>
#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是被线程 5LWP 9511)加锁(拥有)的,而AccontB_mutex是被线程 3LWP 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);

}
.
.
.


[ 本帖最后由 winston 于 2009-5-23 20:53 编辑 ]
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-11-23 20:23 , Processed in 0.014159 second(s), 5 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表