【发布时间】:2010-07-14 11:38:33
【问题描述】:
我有一个服务器-客户端程序,其中服务器和客户端都有多个线程。有可变数量的客户端和服务器(如 3 个服务器(副本)、10 个客户端)。我正在调试该程序中的源文件。我认为存在某种僵局,可能如下:
一个互斥锁已经被一个服务器方法持有,并且来自客户端的请求调用了一个想要再次获取互斥锁的服务器方法。
该程序由一个测试脚本启动,该脚本生成服务器和客户端,并使客户端向服务器发送特定请求。我在代码的可疑区域使用了下面的代码,看看是否有死锁,但似乎不起作用,即代码没有进入任何块:
if (pthread_mutex_lock(&a_mutex) == EDEADLK) {
cout<<"couldnt acquire lock."<<endl;
}
else cout<<"acquired lock"<<endl;
我尝试使用 gdb 进行调试(通过附加一个正在运行的服务器进程)。我为 a_mutex 添加了“显示”和“监视”(在不同的 gdb 运行中)。我得到以下形式的结果:
1: a_mutex = {__data = {__lock = 2, __count = 0, __owner = 4193, __kind = 0, __nusers = 2,
{__spins = 0, __list = {__next = 0x0}}},
__size = "\002\000\000\000\000\000\000\000a\020\000\000\000\000\000\000\002\000\000 \000\000\000\000", __align = 2}
我不知道上述输出中所有内容的含义,但我可以看到一个线程 (4193) 正在持有互斥锁。我看到了那个线程的回溯(剪断):
#0 0xb8082430 in __kernel_vsyscall ()
#1 0xb7e347a6 in nanosleep () from /lib/tls/i686/cmov/libc.so.6
#2 0xb7e345be in sleep () from /lib/tls/i686/cmov/libc.so.6
#3 0x0804cb59 in class1::method1 (this=0xbfa9fe6c, clt=1, id=
{static npos = 4294967295, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0xb7c9c11c "l/%\b"}})
at file1.cc:33
我不知道这个错误是如何以及在哪里。
非常感谢您对以下问题的任何帮助:
- 调试此类条件/程序的好方法是什么?
- 如何检测死锁情况(即锁被持有但未释放的情况)?
- 在这样的多进程程序中,有没有更好的使用gdb的方法? (即检查所有进程中的状态?配置 gdb 在进程开始之前观察/显示变量?)
- 因为,当我在服务器启动后(通过测试程序脚本)将 gdb 附加到服务器时,服务器可能已经提前到我要检查的代码之前。我尝试在可疑区域之前添加 sleep(20) 来帮助我使用 gdb,但我认为这不是一个好方法。我也认为打开多个终端,手动启动服务器和客户端并检查每个终端的状态也不是一个好主意(如果我错了,请纠正我)。
PS:我已经读过这个question了。
非常感谢。
【问题讨论】:
-
我个人使用了英特尔线程检查器。我发现捕获死锁非常有用
-
我也用过 Intel Thread Checker。 hellgrind 工具(Valgrind 的一部分)也很出色。
-
这看起来不像是死锁,而只是争用。您是否有第二个互斥体正在那里的某个地方获得?如果是这样,请确保它们以相同的顺序锁定。