【问题标题】:Why does Timer callback stop being invoked when an Exception is caught?为什么捕获到异常时停止调用 Timer 回调?
【发布时间】:2013-05-15 13:32:09
【问题描述】:

我正在开发一个基本上运行以下代码的 Windows 服务:

public class ServiceController
{
  private FundsEngine _fundsEngine;

  protected override void OnStart(string[] args)
  {
    var logsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
    if (Directory.Exists(logsPath) == false)
    {
      Directory.CreateDirectory(logsPath);
    }

    _fundsEngine = new FundsEngine();
    _fundsEngine.Start();
  }
}

服务可以启动“引擎”,这些引擎只是使用定时器在指定时间间隔执行代码的类。

以下类是使用System.Threading.Timer 每5 秒调用一次回调OnTick() 的引擎示例。

public class FundsEngine
{
  private System.Threading.Timer _timer;
  private static Logger _logger = LogManager.GetCurrentClassLogger();

  public void Start()
  {
    _logger.Trace("Begin Start");

    try
    {
      // details omitted

      _timer = new Timer(OnTick);
      _timer.Change(5000, Timeout.Infinite);
    }
    catch (Exception exception)
    {
      _logger.ErrorException("Error in Start.", exception);
    }
    finally
    {
      _logger.Trace("End Start");
    }
  }

  private void OnTick(object state)
  {
    _logger.Trace("Begin Tick");

    try
    {
      // do stuff
      _timer.Change(5000, Timeout.Infinite);
    }
    catch (Exception exception)
    {
      _logger.ErrorException("Error in Tick. ", exception);
    }
    finally
    {
      _logger.Trace("End Tick");
    }
  }
}

如下面的日志所示,Timer 按预期工作,每 5 秒调用一次OnTick() 方法。

2013-05-14 16:27:01.2261|TRACE|Begin Start 
2013-05-14 16:27:03.8514|TRACE|End Start 
2013-05-14 16:27:08.8569|TRACE|Begin Tick 
2013-05-14 16:27:08.8709|TRACE|End Tick 
2013-05-14 16:27:13.8734|TRACE|Begin Tick 
2013-05-14 16:27:13.8734|TRACE|End Tick 
2013-05-14 16:27:18.8809|TRACE|Begin Tick 
2013-05-14 16:27:18.8809|TRACE|End Tick 
2013-05-14 16:27:23.8894|TRACE|Begin Tick 
2013-05-14 16:27:23.8894|TRACE|End Tick 
2013-05-14 16:27:28.8969|TRACE|Begin Tick 
2013-05-14 16:27:28.8969|TRACE|End Tick 
2013-05-14 16:27:33.9044|TRACE|Begin Tick 
2013-05-14 16:27:33.9044|TRACE|End Tick 

如果在OnTick() 方法中捕获到异常,我的期望是它会被记录,并且服务将继续运行,这样OnTick() 方法将在5 秒内再次被调用。但是,情况并非如此,因为在处理完异常后再也不会调用回调。这是为什么呢?

2013-05-14 16:29:03.8574|TRACE|Begin Start 
2013-05-14 16:29:03.8574|TRACE|End Start 
2013-05-14 16:29:08.8709|TRACE|Begin Tick 
2013-05-14 16:29:09.9750|ERROR|Error in Tick.  System.Net.Sockets.SocketException (0x80004005): No connection could be made because the target machine actively refused it 127.0.0.1:22
2013-05-14 16:29:09.9750|TRACE|End Tick

【问题讨论】:

    标签: c# exception-handling timer callback


    【解决方案1】:
      _timer.Change(5000, Timeout.Infinite);
    

    您没有创建周期计时器,为 period 参数传递 Infinite。计时器只会调用一次 OnTick()。然而,代码非常不完整,唯一可行的方法是再次调用 Change() 为计时器充电。

    这个 Change() 调用被异常绕过的几率非常高。如果你想让它继续下去,那么这个 Change() 调用属于 finally 块。尽管这样做实际上并不是一个好主意,但进程状态已损坏并且它会再次崩溃的可能性非零。一遍又一遍。您至少应该对此采取对策,并计算连续崩溃的次数,当它反复炸弹时放弃。

    【讨论】:

    • 在所有方面都正确。我编辑了我的原始帖子以显示缺失的细节。不知道我是怎么错过的,但这显然是完全合理的。
    【解决方案2】:

    this StackOverflow 帖子上接受的答案指出,如果发生异常...

    System.Threading.Timer 将终止程序。

    我相信这就是你所看到的。

    【讨论】:

    • 我看到了这个,但认为它只是指未处理的异常,如提到的here,但一直无法找到澄清。
    • 所以除了在 try catch 块中获取整个被调用函数之外,我们没有办法处理它们吗?
    猜你喜欢
    • 2019-11-10
    • 2016-02-07
    • 1970-01-01
    • 2012-12-26
    • 2022-12-11
    • 2014-06-30
    • 1970-01-01
    • 2012-01-23
    • 2021-07-04
    相关资源
    最近更新 更多