【问题标题】:.NET Windows Service with timer stops responding带有计时器的 .NET Windows 服务停止响应
【发布时间】:2010-09-28 16:55:02
【问题描述】:

我有一个用 C# 编写的 Windows 服务。它内部有一个计时器,它会定期触发一些功能。所以我的服务的骨架:

public partial class ArchiveService : ServiceBase
{
    Timer tickTack;
    int interval = 10;
    ...
 
    protected override void OnStart(string[] args)
    {
        tickTack = new Timer(1000 * interval);

        tickTack.Elapsed += new ElapsedEventHandler(tickTack_Elapsed);
        tickTack.Start();
    }

    protected override void OnStop()
    {            
        tickTack.Stop();
    }    
    
    private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
    {
        ...
    }
}

它工作一段时间(如 10-15 天)然后停止。我的意思是服务显示为正在运行,但它没有做任何事情。我做了一些记录,问题可能出在计时器上,因为在间隔之后它不会调用 tickTack_Elapsed 函数。

我正在考虑在没有计时器的情况下重写它,使用无限循环,在我设置的时间内停止处理。这也不是一个优雅的解决方案,我认为它可能会对内存产生一些副作用。

Timer 是从 System.Timers 命名空间中使用的,环境是 Windows 2003。我在不同服务器上的两个不同服务中使用了这种方法,但两者都产生了这种行为(这就是为什么我认为它以某种方式连接到我的代码或框架本身)。

有人经历过这种行为吗?有什么问题?


编辑:

我编辑了这两个服务。一个人到处都有很好的尝试捕获和更多的日志记录。第二个定期进行计时器娱乐。自他们以来,他们都没有停止过,所以如果这种情况再持续一周,我将结束这个问题。到目前为止,谢谢大家。


编辑:

我关闭这个问题是因为什么都没发生。我的意思是我做了一些更改,但这些更改与这件事并不真正相关,并且从那时起两个服务都运行没有任何问题。请将其标记为“因不再相关而关闭”。

【问题讨论】:

  • 定时器停止运行后,事件日志中是否有任何内容?
  • 什么都没有。我可以捕捉到 tickTack_Elapsed 函数,但它不再被调用。所以日志显示,从启动服务开始,我每 10 分钟收到一次事件,但过了一会儿它就停止了,没有任何错误消息或其他任何东西。我可以以某种方式记录更多详细信息吗?
  • 不要关闭问题,因为其他人可能会发现该信息有用;改为接受答案

标签: c# windows-services timer


【解决方案1】:

定时器中未处理的异常被吞下,它们默默地杀死定时器

将计时器代码的主体包装在 try-catch 块中

【讨论】:

  • 根据我的经验,这个问题几乎总是由于计时器已过委托线程的未处理异常,即“史蒂文所说的!”
  • 这似乎是可怕的默认行为,但我以前也见过这种情况。
  • 我不敢相信情况仍然如此。尽管我写了大量的日志,但我一直在试图弄清楚为什么我的程序会突然停止而没有任何消息。
  • @spinon:我对 .net 的不满之一 - 这是自 .net 1.0 以来的设计缺陷,但即使在 12 年后仍未修复!
  • @Giorgi:是的 - 否则该方法中的任何异常(在计时器滴答时执行)都会默默地杀死计时器
【解决方案2】:

我以前在计时器和循环服务中都看到过这种情况。通常情况是,捕获到的异常会停止计时器或循环线程,但不会将其作为异常恢复的一部分重新启动。

关于你的其他观点... 我不认为计时器有什么“优雅”的地方。对我来说,在代码中看到循环操作比计时器方法更直接。但优雅是主观的。

内存问题?如果你写得好,就不会。如果您的 Thread.Sleep() 设置不正确,可能是处理器负担。

【讨论】:

  • 我最后的想法是用VS连接到服务来调试它。希望无论发生什么我都能得到例外。我还将其中一个重写为循环。值得一试。
  • 您可能希望有一个循环来定期检查计时器以查看其是否正在运行,或者检查另一个循环。我使用它来自动重新启动停止的计时器或循环线程。
【解决方案3】:

http://support.microsoft.com/kb/842793

这是一个在框架中多次出现的已知错误。

最著名的解决方法:不要使用计时器。我通过执行一个愚蠢的“while (true)”循环使这个错误变得无效。

您的里程可能会有所不同,因此请使用您的操作系统/框架位组合进行验证。

【讨论】:

  • 抱歉,我忘了说这是一个 .NET 2.0 应用程序。但我也不会停止并重新启动计时器,但是有一些要点需要考虑(比如使用 System.Threading 而不是 System.Timers)。我添加到我的列表中尝试,谢谢。
  • 我的效果和你一样——我也从未停止/重新启动计时器。尽管如此,通过详细的日志记录,我能够确定计时器只是停止触发事件。
【解决方案4】:

正如许多受访者指出的那样,异常被计时器吞没了。在我的 Windows 服务中,我使用 System.Threading.Timer。它具有 Change(...) 方法,可让您启动/停止该计时器。可能出现异常的地方可能是重入问题 - 如果 tickTack_Elapsed 执行时间长于计时器周期。通常我这样写定时器循环:

    void TimeLoop(object arg)
    {
        stopTimer();

        //Do some stuff

        startTimer();
    }

你也可以lock(...)你的主循环来防止重入。

【讨论】:

    【解决方案5】:

    有趣的问题。如果它真的只是时间相关(即不是例外),那么我想知道您是否可以简单地定期回收计时器 - 即

    private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
    {
        CheckForRecycle();
        // ... actual code
    }
    
    private void CheckForRecycle()
    {
        lock(someLock) {
            if(++tickCount > MAX_TICKS) {
                tickCount = 0;
                tickTack.Stop();
                // re-create timer
                tickTack = new Timer(...);
                tickTack.Elapsed += ...
                tickTack.Start();
            }
        }
    }
    

    您可以将其中的一部分与OnStart / OnStop 等合并以减少重复。

    【讨论】:

    • 有趣的想法,我这周一定会试一试的。
    【解决方案6】:

    您检查过错误日志吗?也许你不知何故用完了计时器。也许您可以在初始化 ArchiveService 时只创建一个计时器并跳过 OnStart 内容。

    【讨论】:

    • 定时器只创建一次。 OnStart 仅在我启动服务本身时运行,而不是每次它想做某事时运行。
    【解决方案7】:

    我在几个项目中做了和你完全一样的,但没有遇到问题。

    tickTac_Elapsed 中是否有可能导致此问题的代码?就像一个永远不会结束的循环或一些停止计时器的错误,使用线程并等待这些结束等等?

    【讨论】:

    • 很遗憾没有。 tickTack_Elapsed 工作正常,我在它开始和结束时记录。每次我在停止响应之前看到一个开始-停止事件对。此外,我还检查了那里的运行状态,因此它无法运行到以前启动的实例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-01
    • 2012-10-04
    相关资源
    最近更新 更多