5

我们有一个用 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 并不理想,但为什么它永远不会回来?

4

8 回答 8

5

深入了解一下?在那个混蛋身上贴一个调试器!

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

  1. 日志系统挂起;
  2. 线程退出得很好,但服务仍在运行,因为其他部分有逻辑错误。

也许,但几乎可以肯定不是,以下内容:

  • Sleep() 挂起。

但无论如何,附加调试器会显示线程是否仍然存在以及它是否真的挂起。

于 2008-08-27T11:29:58.797 回答
3

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

我认为更好的选择是让您的日志记录系统捕获重复项,以便它可以编写类似“上一条消息重复 N 次”之类的内容。

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

当您说它正在报告您描述的错误时,您的意思是该处理程序正在报告错误吗?我不清楚的原因是在代码片段中你说“出了点问题”,但你没有在描述中这么说;我不希望这变得如此愚蠢,因为异常在其他地方被捕获,并且代码被卡在睡眠以外的其他地方。

于 2008-08-27T10:10:32.513 回答
2

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

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

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

于 2010-07-05T09:59:50.310 回答
0

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

于 2008-08-27T10:09:13.063 回答
0

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

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

于 2008-08-27T12:18:36.123 回答
0

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

于 2008-08-27T12:28:00.623 回答
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 块中,所以任何意外发生的事情都会被记录下来。如果我发现更多,我会更新这个答案。

于 2008-09-22T16:44:35.663 回答
0

在寻找我自己的 Thread.Sleep 问题时偶然发现了这一点。这可能相关,也可能不相关,但是如果您的 doSomething() 引发异常,则不会发生 closeDatabaseConnections() ,这可能会导致资源泄漏。我将其放在 finally 块中。只是想一想。

于 2009-02-13T22:25:33.290 回答