NS编程与调试 - gdb调试工具
2008-11-26 20:15
302 查看
NS[/b]编程与调试 - gdb[/b]调试工具 - [技术讨论]
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://citynight.blogbus.com/logs/11729148.html
gdb[/b]调试工具类似于vc中的debug工具。目前有命令行的和窗口界面的。窗口界面是DDD。我只用了命令行的。用gdb[/b]调试ns2,要注意几点:
1,安装gdb[/b],下载gdb[/b]包,安装了就是了。
2,改写Makefile,使之称为debug版本,具体做法:
在代码里面添加调试信息:修改Makefile(没有任何后缀的)将里面
CCOPT = #如果是ns[/b]-allinone-2.28,这里是CCOPT = -O2
STATIC =
LDFLAGS = $(STATIC)
LDOUT = -o $(BLANK)
改变为:
CCOPT = -g #如果是ns[/b]-allinone-2.28,这里修改为 CCOPT = -O2 -g
STATIC =
LDFLAGS = $(STATIC)
LDOUT = -o $(BLANK)
修改的东西是粉红色字体所示
然后重新编译
注意:以下步骤一个都不能少
Make clean
Make depend
Make3,调试:
建议把我们的测试脚本写在ns[/b]-allinone-2.**/ns[/b]-2.XX/mytclscript/下面
当调试时,首先进入ns[/b]-2.XX文件[/b]夹 [tengda@localhost ~]$ cd ns[/b]-allinone-2.31/ns[/b]-2.31/
然后 [tengda@localhost ns[/b]-2.31]$ gdb[/b] ns[/b]
之后会出现
Copyright (C) 2006 Free Software Foundation, Inc.
GDB[/b] 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[/b]. Type "show warranty" for details.
This GDB[/b] was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
(gdb[/b])
然后在该平台上运行我们的脚本,可以用cd 命令进入我们脚本所在文件[/b]夹。运行我们的脚本:
(gdb[/b]) run mbs.tcl这样就可以进行调试了。具体调试过程与命令,我转载如下:============================================GDB[/b](GNU 项目调试器)可以让您了解程序在执行时“内部” 究竟在干些什么,以及在程序发生崩溃的瞬间正在做什么。GDB[/b] 做以下 4 件主要的事情来帮助您捕获程序中的 bug:在程序启动之前指定一些可以影响程序行为的变量或条件
在某个指定的地方或条件下暂停程序
在程序停止时检查已经发生了什么
在程序执行过程中修改程序中的变量或条件,这样就可以体验修复一个 bug 的成果,并继续了解其他 bug
要调试的程序可以是使用 C、C++、Pascal、Objective-C 以及其他很多语言编写的。GDB[/b] 的二进制文件[/b]名是 gdb[/b]。gdb[/b] 中有很多命令。使用
help命令可以列出所有的命令,以及关于如何使用这些命令的介绍。下表给出了最常用的 GDB[/b] 命令。
表 1. gdb 中最常用的命令[/b]
命令 | 说明 | 例子 |
---|---|---|
help | 显示命令类别 | help- 显示命令类别 help breakpoints- 显示属于 breakpoints 类别的命令 help break- 显示 break 命令的解释 |
run | 启动所调试的程序 | ? |
kill | 终止正在调试的程序的执行 | 通常这会在要执行的代码行已经超过了您想要调试的代码时使用。执行 kill会重置断点,并从头再次运行这个程序 |
cont | 所调试的程序运行到[/b]一个断点、异常或单步之后,继续执行 | ? |
info break | 显示当前的断点或观察点 | ? |
break | 在指定的行或函数处设置断点 | break 93 if i=8- 当变量 i 等于 8 时,在第 93 行停止程序执行 |
Step | 单步执行程序,直到它到达一个不同的源[/b]代码行。您可以使用 s来代表 step 命令 | ? |
Next | 与 step 命令类似,只是它不[/b]会“单步跟踪到[/b]”子例程中 | ? |
打印一个变量或表达式的值 | print pointer- 打印变量指针的内容 print *pointer- 打印指针所指向的数据结构的内容 | |
delete | 删除某些断点或自动显示表达式 | delete 1- 删除断点 1。断点可以通过 info break来显示 |
watch | 为一个表达式设置一个观察点。当表达式的值发生变化时,这个观察点就会暂停程序的执行 | ? |
where | 打印所有堆栈帧的栈信息 | where- 不[/b]使用参数,输出当前线程的堆栈信息 where all- 输出当前线程组中所有线程的堆栈信息 where threadindex- 输出指定线程的堆栈信息 |
attach | 开始查看一个已经运行的进程 | attach <process_id> - 附加到[/b]进程 process_id 上。process_id 可以使用 ps 命令找到 |
info thread | 显示当前正在运行的线程 | ? |
thread apply threadno command | 对一个线程运行 gdb[/b] 命令 | thread apply 3 where- 对线程 3 运行 where命令 |
Thread threadno | 选择一个线程作为当前线程 | ? |
# gdb[/b] programname corefilename |
# gdb[/b] -c core programname |
ulimit –c unlimited。清单 8 中的例子阐述了如何使用 gdb[/b] 来定位程序中的 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 |
清单 10. 调用 gdb[/b]
# gdb[/b] ./gdbtest1 GNU gdb[/b] 6.2.1 Copyright 2004 Free Software Foundation, Inc. GDB[/b] 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[/b]. Type "show warranty" for details. This GDB[/b] was configured as "ppc-suse-linux"...Using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb[/b]) |
run和
where命令来精确定位段错误发生在程序中的什么位置。
清单 11. 执行 run 和 where 命令
(gdb[/b]) 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[/b]) 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[/b]) |
NumBox<int>::GetNext (this=0x0)接收到[/b]一个段错误。这个数字框上 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; |
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 |
清单 14. 再次使用 gdb 进行查看[/b]
# gdb[/b] ./gdbtest2 GNU gdb[/b] 6.2.1 Copyright 2004 Free Software Foundation, Inc. GDB[/b] 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[/b]. Type "show warranty" for details. This GDB[/b] was configured as "ppc-suse-linux"...Using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb[/b]) break 94 if i==8 Breakpoint 1 at 0x10000968: file gdbtest2.cpp, line 94. (gdb[/b]) 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); |
break 94 if i==8,可以在 i 等于 8 时在第 94 行处停止程序。然后
单步跟踪到[/b]
RemoveBox()函数中。
清单 15. 单步跟踪到 RemoveBox() 函数中[/b]
(gdb[/b]) s 38 NumBox<T> *temp = 0; (gdb[/b]) s 40 while (current != 0) { (gdb[/b]) print pointer $1 = (NumBox<int> *) 0x100120a8 (gdb[/b]) print *pointer $2 = {Num = 0, Next = 0x0} (gdb[/b]) |
kill删除原来的断点,然后添加一个 i 等于 9 时的新断点,然后再次运行这个程序。
清单 16. 在 gdb 中重新启动程序[/b]
(gdb[/b]) kill Kill the program being debugged? (y or n) y (gdb[/b]) 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[/b]) delete 1 (gdb[/b]) break 94 if i==9 Breakpoint 2 at 0x10000968: file gdbtest2.cpp, line 94. (gdb[/b]) 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[/b]) |
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[/b]) s NumChain<int>::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200) at gdbtest2.cpp:37 37 NumBox<T> *current = pointer; (gdb[/b]) display *pointer 1: *this->pointer = {Num = 9, Next = 0x10012098} (gdb[/b]) s 38 NumBox<T> *temp = 0; 1: *this->pointer = {Num = 9, Next = 0x10012098} (gdb[/b]) s 40 while (current != 0) { 1: *this->pointer = {Num = 9, Next = 0x10012098} (gdb[/b]) s 41 if (current->GetValue() == item_to_remove) { 1: *this->pointer = {Num = 9, Next = 0x10012098} (gdb[/b]) s NumBox<int>::GetValue (this=0x100120a8) at gdbtest2.cpp:16 16 const T& GetValue () const { return Num; } (gdb[/b]) 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[/b]) s 44 if (current->GetNext() == 0) { 1: *this->pointer = {Num = 9, Next = 0x10012098} (gdb[/b]) s NumBox<int>::GetNext (this=0x100120a8) at gdbtest2.cpp:14 14 NumBox<T>*GetNext() const { return Next; } (gdb[/b]) 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[/b]) s ~NumBox (this=0x100120a8) at gdbtest2.cpp:10 10 std::cout << "Number Box " <<"/"" << GetValue() <<"/"" <<" deleted" << std::endl; (gdb[/b]) s NumBox<int>::GetValue (this=0x100120a8) at gdbtest2.cpp:16 16 const T& GetValue () const { return Num; } (gdb[/b]) s Number Box "9" deleted ~NumBox (this=0x100120a8) at gdbtest2.cpp:11 11 Next = 0; (gdb[/b]) 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[/b]) s 53 return 0; 1: *this->pointer = {Num = 0, Next = 0x0} (gdb[/b]) s 0x10000d1c 66 return -1; 1: *this->pointer = {Num = 0, Next = 0x0} |
list->pointer在删除 Number Box "9" 之后指向了 Number Box "0"。这个逻辑并不[/b]正确,因为在删除 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; |
清单 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 |
清单 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 -g -o gdbtest2 gdbtest2.c -L/lib/tls -lpthread |
All the money is transferred !!消息。将 gdb[/b] 附加到[/b]正在运行的进程上,从而了解这个进程内部正在发生什么。
清单 21. 将 gdb 附加到[/b]正在运行的进程上[/b]
# 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[/b] -pid 9510 GNU gdb[/b] 6.2.1 Copyright 2004 Free Software Foundation, Inc. GDB[/b] 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[/b]. Type "show warranty" for details. This GDB[/b] 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[/b]) 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[/b]) |
info thread命令中,我们可以了解到[/b]除了主线程(thread #1)之外的所有线程都在等待函数
__lll_lock_wait ()完成。使用
thread apply threadno where命令来查看每个线程到底运行到了什么地方:
清单 22. 查看每个线程运行到了什么地方
(gdb[/b]) 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[/b]) 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[/b]) 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[/b]) 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[/b]) 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[/b]) print AccountA_mutex $1 = {__m_reserved = 2, __m_count = 0, __m_owner = 0x2527, __m_kind = 0, __m_lock = {__status = 1, __spinlock = 0}} (gdb[/b]) print 0x2527 $2 = 9511 (gdb[/b]) print AccountB_mutex $3 = {__m_reserved = 2, __m_count = 0, __m_owner = 0x2529, __m_kind = 0, __m_lock = {__status = 1, __spinlock = 0}} (gdb[/b]) print 0x2529 $4 = 9513 (gdb[/b]) |
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); } . . . |
相关文章推荐
- NS编程与调试 - 内存调试工具 valgrind
- Linux下编程工具的使用(5) - GDB调试工具(1)
- Linux下编程工具的使用(5) - GDB调试工具(2)
- NS2编程与调试-gdb调试工具
- 调试工具GDB详解
- Libheap:一款用于分析Glibc堆结构的GDB调试工具
- gdb调试工具使用方法分享
- Makefile管理工具与GDB调试工具学习笔记
- 常用调试工具gdb,dbx,valgrind介绍一
- Android系统开发(2)——GDB调试工具
- gdb调试工具vi编译器命令参考网址
- linux gdb调试工具简介【一】
- gdb调试工具
- 编程工具系列之二------使用GDB的源代码查看功能
- GDB调试工具学习笔记
- Linux下C编程+GDB调试
- linux命令之调试工具gdb
- Linux 网络编程 调试工具
- Android 中运行GDB调试工具的方法
- linux开发调试工具---GDB的使用