【问题标题】:How do I gracefully handle this exception in a background thread in a Windows service?如何在 Windows 服务的后台线程中优雅地处理此异常?
【发布时间】:2014-09-08 12:44:30
【问题描述】:

我正在使用 C# .NET 4.0。

我有一个 Windows 服务。此 Windows 服务启动一个后台线程。此后台线程对 Win32 API 进行 P/Invoke 调用,并且非常间歇性地(在 24 小时内以 1 秒为间隔大约一次或两次)Win32 函数将返回垃圾。我尽我最大的努力在不引发异常的情况下处理这些垃圾,但最终还是会发生异常。当它发生时,它会终止我的服务,即使我正在使用捕获异常的 try/catch。

using System.Security.Principal;

Thread awesomeThread;

protected override void OnStart(string[] args)
{  
    ThreadStart awesomeThreadThreadStart = new ThreadStart(AwesomeThread);
    awesomeThread = new Thread(awesomeThreadThreadStart);
    awesomeThread.IsBackground = true;
    awesomeThread.Start();
}

private void AwesomeThread()
{
    while (serviceStarted)
    {
         if (serviceStarted)
             Thread.Sleep(1000)
         else
             break;

        //
        // WinApi calls happen here. Once every few hours, they return gibberish.
        //
        NTAccount account = new NTAccount(domain, username);
        SecurityIdentifier sid = null;
        try
        {
             sid = (SecurityIdentifier)account.Translate(typeof(SecurityIdentifier));                       
        }
        catch (Exception ex)
        {
             Eventlog.WriteEntry("Oh no an exception occurred: " + ex.Message);
        }
        // Resource cleanup stuff
    }
}

因此,当account.Translate() 上确实发生异常时,会捕获异常并写入事件日志消息,此时线程可以安全地继续执行...但是。 NET 杀死了它,从而杀死了我的服务。我可以处理异常并让后台线程继续执行吗?

目前,作为一种解决方法,我已将 Windows 服务设置为在服务控制器中自动重启,因此我可以处理服务每天重启一到两次,但如果可以的话,我宁愿阻止它。

【问题讨论】:

  • 您可能希望在 while 循环中的所有内容中都使用 try catch。此外,我通常会使用 .ToString() 方法而不是 .Message 来记录异常。您将获得有关异常的更多详细信息。除此之外,请确保使用要部署的 dll/exe 部署 pdb 文件,以确保异常详细信息中包含行号。如果未捕获异常,是否有可能您没有尝试捕获您需要的所有内容?
  • @ColeW 感谢您的反馈,但我已经知道确切的异常是什么——我不需要更多关于异常是什么、发生位置或发生原因的详细信息。该异常仅发生在我包含在 try 块中的单个语句中。我不明白的是,为什么即使我捕获了异常, catch 块中的代码运行之后,线程和整个进程仍然终止。
  • 我们在使用一个非常大的 ERP 系统应用程序提供商的第三方库时遇到了类似的情况。突然发生了一个错误,无法捕获,但会记录在事件日志中。之后,服务就退出了。在尝试解决了许多不成功的小时后,我们提供了第二个服务,它只监视并重新启动第一个服务。这可能无法解决您的问题,但也许您不再感到孤单……

标签: c# .net multithreading exception-handling


【解决方案1】:

这并不是真正的答案,更多的是评论,但我讨厌 cmets 中代码格式不佳。

您是否 100% 确定该语句中的异常是您唯一的问题?我建议您将以下内容添加到您的程序中:

     // Create AppDomain ProcessExit and UnhandledException event handlers
     AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
     AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

当然还有事件处理程序:

  /// <summary>
  /// Method called when the process is exiting.
  /// </summary>
  private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
  {
     // do some logging?
  }


  /// <summary>
  /// Method called if an unhandled AppDomain exception occurs.
  /// </summary>
  private static void CurrentDomain_UnhandledException(object sender,
                                                       UnhandledExceptionEventArgs e)
  {
     // do some logging?
  }

此时您无法保存服务,但您可能会获得一些有用的信息。

编辑:

刚刚注意到我复制并粘贴了一些事件处理程序标记为“静态”的代码,但这不是必需的。

【讨论】:

  • 谢谢 - 我要试试这个......但由于我无法按需重现异常,我可能需要一两天的时间来报告。
【解决方案2】:

检查 Windows 事件日志以查看在进程退出时 .NET 是否报告了任何错误。这通常会提供有关进程为何死亡的有用信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-10
    • 2011-04-30
    • 2015-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-30
    相关资源
    最近更新 更多