调试多线程服务器

时间:2014-10-07 13:35:43

标签: c++ multithreading thread-safety pthreads

我在接受采访时被问到这一点,现在我很好奇,因为我不认为面试官对我的回答感到满意。这是个问题:

多线程服务器应用程序停止工作,应用程序的最后一条日志消息是:

"Some Server Related Message..."

代码如下:

CalledFunc ()
{
    Code ...

    Acquiring Thread lock
    Line printing "Some Server Related Message..."
    Func();
    Releasing Thread Lock
}
  1. 程序员应该怎么做才能调试这个?
  2. Func()
  3. 发生了什么问题
  4. 如果在Func()中引发异常,应该采取什么措施来解决问题?

4 个答案:

答案 0 :(得分:1)

原因#1:这是一个数据库问题。 这可能听起来很奇怪,但应用程序服务器挂起的主要原因与应用程序服务器本身没有直接关系。症状的位置很少是根本原因的位置。以下情况很常见:

数据库存在瓶颈,导致查询运行速度比平常慢。 过去需要1秒的请求,现在需要5秒才能完成。 平均并发请求数缓慢增加(由于积压)。 服务器用尽线程,应用程序服务器挂起。 如果你设法获得一个线程转储,你只会看到一堆线程正在等待,而另一个组实际上正在运行。另一种可能性是等待线程(或排队线程)的数量将吞噬所有可用内存,并最终导致OutOfMemory错误。

原因#2:死锁。 如果应用程序服务器似乎无效,请查找死锁。这些可能是导致SQL查询挂起或寻找更新语句的数据库死锁。例如,如果日志表被锁定,则为每个请求写入数据库的事务日志可能会轻易挂起整个应用程序。还要检查共享对象 - 一次从多个线程写入的操作系统文件。

原因#3:失控线程。 在应用程序服务器确实应该受到责备的情况下,您应该寻找一个失控的线程。这些很难被发现,因为它们几乎不会出现在日志中,因为它们通常只在请求完成时才会被写入。一个失控的线程可能不会返回,直到它已经影响整个应用程序。因此,挂起请求不会写入日志。这些“失控”线程通常包含无限循环或代码,导致消耗过多的堆内存导致内存不足。例如,应该显示结果不包括结果页面之间的分页选项的查询突然需要显示大量结果。该页面将永远呈现并破坏应用程序服务器,最终导致它挂起。

答案 1 :(得分:0)

可能是:

  • Func()正试图再次获得锁定(易于检查)或
  • Func()在锁定锁定(更可能和更微妙)
  • 时抛出异常

所以:

  1. 检查Func()的代码以检查所有可能的路径(包括例外)是否释放锁
  2. 上面两个选项之一
  3. 在抛出异常之前释放锁定或在CalledFunc()中捕获异常并释放锁定

答案 2 :(得分:0)

要解决Func()中的异常问题,您可以使用范围锁。 RAII是确保异常安全并避免一般泄漏的好方法。该链接也恰好以互斥为例。

此外,在日志中看到该行并不意味着问题来自代码的这一部分。

答案 3 :(得分:0)

我认为他们在寻找这个:

  

程序员应该怎么做才能调试它?

获取进程的挂起转储,然后使用windbg找出原因,即如果它是死锁,那么它将从转储中显而易见。

  

Func()中发生了什么问题?

从下一个问题的问题我们可以假设它必须抛出一个异常,导致锁永远不会被释放,或者它试图再次锁定导致死锁。

  

如果在Func()中抛出异常,应该采取什么措施来修复   问题?

使用RAII是异常安全的,以及更好/更清晰的代码。