【问题标题】:Timer in Windows Service not firing ElapsedEventHandlerWindows 服务中的计时器未触发 ElapsedEventHandler
【发布时间】:2011-08-17 14:37:46
【问题描述】:

我有一个用 C# 编写的 Windows 服务,可以正确执行一个方法。我添加了一个计时器来安排方法执行,它似乎没有触发 ElapsedEventHandler 事件。

System.Timers.Timer timer = new System.Timers.Timer();

public LabelService()
        {
            InitializeComponent();
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
        }


public void SetTimer()
        {
            DateTime nextRunTime = GetNextRunTime();
            var ts = nextRunTime - DateTime.Now;
            timer.Interval = ts.TotalMilliseconds;
            timer.AutoReset = false;
            timer.Start();
        }

void timer_Elapsed(object source, ElapsedEventArgs e)
        {
           // ** never gets here **
            timer.Stop();
              // run some code
            SetTimer();
        }

我可以运行并在timer.Start(); 处打断点,所以我知道这已经完成,但它永远不会落入 timer_Elapsed 方法。 (为了测试,我将 ts.TotalMilliseconds 更改为 1000)有什么想法吗?

【问题讨论】:

  • 我尝试将 timer.Interval 和 timer.AutoReset 移出 SetTimer() 并且没有变化。
  • 您能详细介绍一下您的课程和周边代码吗?这段代码是否有可能在计时器启动之前从内存中卸载的东西中运行?如果对象不再存在,则事件不会触发...
  • 当然。我的课程基本上就是我在上面发布的内容,以及一些不会产生任何效果的辅助方法。它与计时器有关,因为如果我直接从 OnStart() 或 Main() 调用 timer_Elapsed 它执行得很好。我一直打断点直到 timer.Start() 所以调试工作正常。我错过了一些东西......我的课程是:公共部分类 LabelService:ServiceBase。我认为这看起来是正确的?
  • 您是否完全确定事件处理程序实际上已连接到事件?只是为了好玩,尝试移动 timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);进入你的 SetTimer() 方法,然后 timer.Elapsed -= new ElapsedEventHandler(timer_Elapsed);就在处理程序中的 timer.Stop() 之后。只是看看你能不能参加这个活动......
  • Jim - 刚刚尝试了您的建议,但在 timer.Start() 之后没有任何反应。我可以在那里放置一个断点。它退出 SetTimer() 并且没有其他任何事情发生。我在 timer_Elapsed 最开始放置的任何测试代码都不会被命中。我很确定我正确地添加了处理程序,方法是输入 timer.Elapsed += 并点击两次 tab 来创建处理程序。

标签: c# timer


【解决方案1】:

"如果 Enabled 设置为 true 且 AutoReset 设置为 false,则 Timer 仅引发一次 Elapsed 事件,即间隔时间第一次流逝。当 Enabled 为 true 且 AutoReset 为 true 时,Timer 继续引发 Elapsed 事件在指定的时间间隔内。”

所以我认为你必须设置

timer.AutoReset = true;

【讨论】:

  • timer.Enabled 与我的 SetTimer 方法中的 timer.Start 相同。
  • 我设置了 timer.AutoReset = true;并且没有变化。 timer_Elapsed 方法永远不会被调用。
  • 等等。为什么每次都设置Elapsed。不要那样做。
  • 没错,我把它移出了SetTimer()。但仍然没有触发事件。
  • 要对原始帖子发表评论,您只需设置 timer.autoreset = true 如果您希望事情不断重复。如果您只希望该计时器运行一次,则可以将其设置为 false。这个值肯定不会对它第一次运行产生影响。
【解决方案2】:

我知道这是旧的,但对于其他有同样问题的人,我可以通过使用来解决这个问题;

public void StartTimer()
{
    _timer.Interval = _pollingIntervalMilliseconds;
    _timer.Enabled = true;
    _timer.AutoReset = false; // We must manually restart the timer when we have finished processing
    _timer.Elapsed += CheckForUpdates;
    _timer.Start();
    if (Environment.UserInteractive)
    {
        Console.WriteLine("System now running, press a key to Stop");
        Console.ReadKey();
    }
}
private void CheckForUpdates(object sender, ElapsedEventArgs e)
{
    Console.WriteLine("Checking For Update");
    DoSomethingSlow();
    _timer.Start(); // restarts the timer to hit this method again after the next interval
}

它会一直触发 Elapsed Event 直到你按下一个键退出

【讨论】:

    【解决方案3】:

    来自 cmets 你说你这样称呼它的问题:

    #if (!DEBUG) 
        ServiceBase[] ServicesToRun; 
        ServicesToRun = new ServiceBase[] { new LabelLoader() }; 
        ServiceBase.Run(ServicesToRun); 
    #else 
        LabelLoader ll = new LabelLoader(); 
        ll.Start(); 
    #endif
    

    如果您处于调试模式,则意味着您的主要方法是这样的:

        LabelLoader ll = new LabelLoader(); 
        ll.Start(); 
    

    这意味着一旦运行了这两行,程序就完成了运行并可能退出。不管你的定时器在做什么,程序已经退出,因此你的定时器永远不会触发。

    我建议用更好的安全带测试你的 ll。就我个人而言,我使用的是 winform 类型的界面,并且只有一个启动按钮来模拟服务启动(然后您的代码将在按钮中单击)。一旦我认为我可以按照自己的意愿运行该代码,我就会在服务环境中对其进行测试。

    【讨论】:

    • 是的,那是我的 Main() 代码。这是我的第一个获胜服务,所以我不确定调试和测试的正确方法。您能否通过在服务环境中对其进行测试来扩展您的意思?服务中的代码按我想要的方式工作,只是计时器没有触发问题。那么我接下来的步骤是什么?
    • 基本上,“在服务环境中”是指将您的代码安装为服务并让 Windows 启动它。所以我会放弃你的调试代码,让服务像在实时环境中一样运行和持久化。在您的计算机上将其作为服务运行,然后以这种方式进行测试。如果您需要调试它,您仍然可以将调试器附加到它(通过附加到进程)。
    • 安装好了,谢谢!一定是我调试它的方式。
    猜你喜欢
    • 2016-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    相关资源
    最近更新 更多