【问题标题】:deadlock detection in multithreaded application多线程应用程序中的死锁检测
【发布时间】:2014-07-19 17:28:56
【问题描述】:
我正在使用使用 posix 线程的多线程 C++ 应用程序,即通过 pthread_create 创建线程。有几个信号量控制同步。信号量主要有两种:
互斥信号量 - pthread_mutex_lock 和 pthread_mutex_unlock 调用之间互斥下的关键部分代码(由同一线程完成)
同步信号量 - 一个线程等待调用 sem_wait 以完成某些任务,其他线程在完成任务后通过 sem_post 发出信号。
在处理大量数据期间,应用程序在运行较长时间时似乎没有响应。
我想到的两种可能性:
- 出现死锁,两个线程互相等待(循环等待)
- 父进程(telnet 会话)超时,导致向子进程发送 SIGHUP 信号。
问题:
- 能否通过日志检测死锁?例如,在每次等待/发布时,在 sem_wait 之前,记录为将要等待,在 sem_wait 获得锁之后,在 sem_post 之后等待(无论如何都是非阻塞的),记录为等待进程的信号/发布——那么如果程序似乎挂起,检查日志以检测任何循环等待。有没有更好的方法推荐?
- 使用 nohup 运行应用程序,以便可以忽略 SIGHUP。
还有其他建议吗?
【问题讨论】:
标签:
c++
multithreading
posix
solaris
semaphore
【解决方案1】:
检测死锁是前期设计的问题。 您不应将应用程序设计为检测死锁,而应努力通过审查和测试将其从设计中消除。
避免/根除设计中的死锁的策略
- 静态分析工具(Coverity Prevent、
clang's --analyze 等)
- 测试
- RAII
一旦您发现了一个死锁,它们通常很容易调查。与很难追溯到其起源的堆损坏不同,死锁系统将一直处于不良状态,直到您前来拯救它。附加您的调试器并查看堆栈跟踪,问题应该很明显。
【解决方案2】:
死锁检测可以在更高级别进行,对于进程,死锁检测可以在操作系统级别进行,对于线程,如果子线程不需要任何系统,主线程可以检测子线程之间的死锁-级别资源,如 I/O 等。
检测死锁的一种方法是为共享资源构建资源需求图。假设系统创建了 2 个线程 Ta 和 Tb,Ta 和 Tb 都需要资源 Ra 和 Rb。如果 Ta 获得了 Ra,并且需要 Rb,这可以像一个有向图:Ra->Ta->Rb。如果 Tb 持有 Rb,这将像 Ra->Ta->Rb->Tb,没有死锁。但是,如果 Tb 持有 Rb 并且需要 Ra,那么图形会是这样的:Ra->Ta->Rb->Tb->Ra,这就构成了一个循环,这意味着死锁。
对于这种特殊情况,我认为可以从日志中检测死锁,如上,说Ta log这样:Ra->Ta->Rb,Tb log这样:Rb->Tb->Ra,然后主线程可以检查是否有循环,但这可能会复杂且昂贵,因此,更好的方法是谨慎使用同步协议,并防止死锁。