关于 mutex 的调试实例

来源:互联网 发布:网络兼职广告 编辑:程序博客网 时间:2024/04/30 10:21

今天解决了一个关于 mutex 的 bug.
程序每次登录成功就会创建两个线程.  sign out 的时候可能会强制 Terminate 这两个线程.
当程序出现问题时用 Process Explorer 观察各个线程. 发现其中一个线程一直在等一个对象, 
打开 windbg, 查看 WaitForSingleObject() 的参数. 找到了这个对象的句柄 6d0. 在 windbg 中执行:

0:001>!handle 6d0 f
Handle 6d0
  Type          Mutant
  Attributes    0
  GrantedAccess 0x1f0001:
         Delete,ReadControl,WriteDac,WriteOwner,Synch
         QueryState
  HandleCount   4
  PointerCount  8
  Name         none
  Object Specific Information
    Mutex is Owned
 
知道了这是一个 mutex. 我用 windbg 也不太熟. google 了一下 windbg  mutex. 有所收获.
用这个帖子里的方法: http://blogs.thinktecture.com/ingo/archive/2006/08/05/414674.aspx
可以找到是那个线程拥有了这个 mutex
运行 kd, 发现是恰好是另一个线程获得了这个 mutex. 查看代码, 发现在线程中有这样的代码:

 ...
 if (WaitForSingleObject(hmutex, 100) != WAIT_OBJECT_0) return FALSE;
 return TRUE;
  
如果返回 TRUE, 则认为等到这个 mutex, 操作完成之后, 会调用 ReleaseMutex() 释放这个 mutex. 如果返回 FALSE, 则不会调用 ReleaseMutex().
 
问题就出在这里. 因为线程可能被强制结束. 那么就有可能没有释放 mutex. 这种情况下, MSDN 的描述是:
 
 If a thread terminates without releasing its ownership of a mutex object, the mutex object is considered to be abandoned. A waiting thread can acquire ownership of an abandoned mutex object, but the wait function will return WAIT_ABANDONED to indicate that the mutex object is abandoned.
 
下一个线程在等这个"被抛弃"的 mutex 时. WaitForSingleObject() 的返回值是 WAIT_ABANDONED, 而不是 WAIT_OBJECT_0. 而且, 这种情况下, 线程的确获得了 mutex 的控制权. 但上面的代码没有考虑这种情况. 还是返回 FALSE,  导致后继的 ReleaseMutex() 没有调用. 因此导致另一个线程被死锁.
 
几点思考:
 1. 一定不要强制结束线程. 反复强调这一点. 但程序员们还是照用不误.
 2. 调用 API 的时候对于返回值的处理要很小心.

PS: 关于 Process Explorer 查看调用栈. 需要几个前提:
 . 安装最新的 Process Explorer
 . 安装最新的 windbg
 . 设置好 _NT_SYMBOL_PATH, 比如:SRV*e:/symbols*http://msdl.microsoft.com/download/symbols
 . 使用命令 symchk /r %windir% 将符号下载到本地. 这个比较费时, 可能要下载超过 1G 的符号文件
 . 在 Process Explorer 菜单 Options/Configure Symbols 里设置正确的 Dbghelp.dll 路径以及 Symbols Path (默认是 _NT_SYMBOL_PATH 的值)
 
这些做好之后, 就可以在 Process Explorer 双击一个进程, 切换到 Threads 页. 等初始化完成之后, 双击一个线程, 就可以看到调用栈了.  

原创粉丝点击