线程没有从Thread.Sleep()唤醒

时间:2008-08-27 10:05:03

标签: .net multithreading

我们有一个用C#编写的Windows服务。该服务产生一个执行此操作的线程:

private void ThreadWorkerFunction()
{
  while(false == _stop) // stop flag set by other thread
  {
    try
    {
      openConnection();

      doStuff();

      closeConnection();
    }
    catch (Exception ex)
    {
      log.Error("Something went wrong.", ex);

      Thread.Sleep(TimeSpan.FromMinutes(10));
    }
  }
}

当数据库消失后,我们将Thread.Sleep放入了几次,然后我们回到3Gb日志文件中,这些文件充满了数据库连接错误。

这几个月一直运行良好,但最近我们看到一些实例,其中log.Error()语句记录了一个“System.InvalidOperationException:这个SqlTransaction已经完成;它不再可用”异常然后从来没有永远回来了。该服务可以保持运行数天,但不会记录任何其他内容。

做了一些阅读之后,我知道Thread.Sleep不理想,但为什么它永远不会回来?

8 个答案:

答案 0 :(得分:5)

挖掘并找出答案?把调试器贴在那个混蛋上!

我至少可以看到以下几种可能性:

  1. 日志记录系统挂起;
  2. 线程退出很好,但服务仍在运行,因为其他部分有逻辑错误。
  3. 也许,但几乎可以肯定的是,以下内容:

    • 睡觉()挂起。

    但无论如何,附加一个调试器会告诉你线程是否仍在那里以及它是否真的挂起了。

答案 1 :(得分:3)

  

当数据库消失后,我们将Thread.Sleep放入了几次,然后我们又回到了3Gb日志文件中,这些文件充满了数据库连接错误。

我认为更好的选择是让你的日志记录系统陷入重复,这样就可以写出“之前的消息重复了N次”。

假设我已经写了一个关于如何在最后可能的时刻打开你的连接并尽早关闭它的标准说明,而不是以你完成它的方式跨越一个潜在的巨大功能(但也许是是您的示范代码的人工制品,您的应用程序实际上是正确编写的。)

当您说它报告您描述的错误时,您是否意味着此处理程序报告错误?我不清楚的原因是在代码片段中你说“出了问题”,但你没有在你的描述中说出来;我不希望这是一个如此愚蠢的东西,因为异常被其他地方捕获,并且代码被卡在除睡眠之外的其他地方。

答案 2 :(得分:2)

我遇到了完全相同的问题。将Sleep行移到异常处理程序之外可以解决我的问题,如下所示:

bool hadError = false;
try {
  ...
} catch (...) {
  hadError = true;
}
if (hadError)
  Thread.Sleep(...);

中断线程似乎在异常处理程序的上下文中不起作用。

答案 3 :(得分:0)

您是否尝试过使用Monitor.Pulse(确保您的线程在运行之前使用线程管理)来让线程执行某些操作?如果可行,那么您将不得不更多地了解线程逻辑。

答案 4 :(得分:0)

从您发布的代码中,不清楚在抛出异常后系统肯定能够重启 - 例如如果异常来自doStuff(),那么控制流将返回(在10分钟等待之后)到openConnection(),而不会通过closeConnection()。

但正如其他人所说,只需附加一个调试器并找到它的实际位置。

答案 5 :(得分:0)

尝试Thread.Sleep(10 * 60 * 1000)

答案 6 :(得分:0)

我从未完全弄清楚发生了什么,但它似乎与在10分钟睡眠期间抛出的ThreadInterruptedExceptions有关,所以我改为代码:

private void ThreadWorkerFunction()
{
  DateTime? timeout = null;

  while (!_stop)
  {
    try
    {
      if (timeout == null || timeout < DateTime.Now)
      {
        openDatabaseConnections();

        doStuff();

        closeDatabaseConnections();
      }
      else
      {
        Thread.Sleep(1000);
      }
    }
    catch (ThreadInterruptedException tiex)
    {
      log.Error("The worker thread was interrupted... ignoring.", tiex);
    }
    catch (Exception ex)
    {
      log.Error("Something went wrong.", ex);

      timeout = DateTime.Now + TimeSpan.FromMinutes(10);
    }
  }
}

除了专门捕获ThreadInterruptedException之外,这只是感觉更安全,因为所有睡眠都发生在try块中,因此将记录任何意外发生的事件。如果我发现更多信息,我会更新这个答案。

答案 7 :(得分:0)

在寻找我自己的Thread.Sleep问题时偶然发现了这一点。这可能有也可能没有关系,但是如果你的doSomething()抛出异常,那么closeDatabaseConnections()就不会发生,这有可能造成资源泄漏..我会把它放在finally块中。只是想一想。