在Windows服务中使用计时器 - 即使禁用计时器,已过时的事件处理程序也会继续触发

时间:2012-07-24 00:55:34

标签: c# windows inheritance service timer

我已经阅读了很多与Windows服务和定时器使用相关的帖子,但我没有找到任何理由仍然触发我的事件处理程序。有人能指出我正确的方向吗?我想知道为什么这种情况正在发生,所以我明白将来如何避免这种情况。

编辑:永远不会调用onError事件处理程序(或者我会在事件日志中看到该事件)。

计时器: System.Timers.Timer
ServiceBase: System.ServiceProcess.ServiceBase


这是抽象类:

public abstract class ABCService : ServiceBase
{
    // Members
    protected Timer             invocationTimer;
    protected Timer             wellnessTimer;
    protected FileSystemWatcher fsw;


    // Constructors
    protected ABCService()
    {
        invocationTimer = new Timer();
        wellnessTimer   = new Timer();
        fsw             = null;

        invocationTimer.AutoReset = false;
        invocationTimer.Interval  = 30000; // 30 seconds
        invocationTimer.Elapsed  += new ElapsedEventHandler(invocationTimer_Elapsed);

        wellnessTimer.AutoReset   = false;
        wellnessTimer.Elapsed    += new ElapsedEventHandler(wellnessTimer_Elapsed);
    }


    // Methods
    protected void invocationTimer_Elapsed(object o, ElapsedEventArgs args)
    {
        try
        {
            // log to event log

            invocationTimer.Stop();

            if ((new FileInfo(fsw.Path + "\\" + fsw.Filter)).Exists)
            {
                onCreated(this, new FileSystemEventArgs(WatcherChangeTypes.Created, fsw.Path, fsw.Filter));
            }
        }
        catch (Exception x)
        {
            onError(this, new ErrorEventArgs(x));
        }
    }

    protected void wellnessTimer_Elapsed(object o, ElapsedEventArgs args)
    {
        try
        {
            // log to event log

            wellnessTimer.Stop();
            wellnessTimer.Interval = 60000; // ms

            if (fsw != null)
            {
                fsw.Dispose();
            }

            fsw = new FileSystemWatcher(ConfigurationManager.AppSettings["pathKey"], ConfigurationManager.AppSettings["filterKey"]);

            invocationTimer.Start();
        }
        catch (Exception x)
        {
            onError(this, new ErrorEventArgs(x));
        }
    }

    protected abstract void onCreated(object o, FileSystemEventArgs args);

    protected virtual void onError(object o, ErrorEventArgs args)
    {
        // log to event log

        wellnessTimer.Start();
    }

    protected override void OnStart(string[] args)
    {
        // log to event log

        wellnessTimer.Interval = 5000; // 5 seconds
        wellnessTimer.Start();
    }

    protected override void OnStop()
    {
        // log to event log

        wellnessTimer.Stop();
    }
}

这是一个实例类:

public partial class Service1 : ABCService
{
    // Members
    private static object locket = new object();
    private static DateTime LAST_RUN_TIME = DateTime.Now.AddSeconds(-10);


    // Constructors
    public Service1()
    {
        InitializeComponent();
    }


    // Methods
    protected override void onCreated(object o, FileSystemEventArgs args)
    {
        lock (locket)
        {
            // log to event log

            if ((DateTime.Now - LAST_RUN_TIME).Seconds >= 10)
            {
                // do stuff
            }
            else
            {
                // log to event log

                invocationTimer.Stop();
                invocationTimer.Start();
            }
        }
    }
}

以下是分部类的自动生成代码:

partial class Service1
{
    /// <summary> 
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Component Designer generated code

    /// <summary> 
    /// Required method for Designer support - do not modify 
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        // 
        // Service1
        // 
        this.ServiceName = "Service1";

    }

    #endregion
}

究竟发生了什么?我正在查看我的事件日志,我看到每分钟调用一次wellnessTimer事件处理程序。

以下是我认为正在发生的事情,但我显然是错的:

1. Service is started via MMC
2. OnStart() method is invoked
3. wellnessTimer interval is set to 5 seconds
4. wellnessTimer start method is invoked
5. wellnessTimer_Elapsed event handler is invoked
6. wellnessTimer stop method is invoked
7. wellnessTimer interval is set to 5 minutes
8. invocationTimer start method is invoked
9. 30 seconds later, the invocationTimer_Elapsed method is invoked
10. invocationTimer stop method is invoked

此时,此实例的两个计时器仍应存在,但应禁用。我通过附加到Visual Studio 2010中的进程调试了这个,并标记了传递给事件处理程序的对象(发送者)的ID。它与实例是同一个对象。此外,Locals窗口中的两个计时器都将其enabled属性设置为false。

这让我觉得我正在使用继承错误,或者正在进行线程化。我不是最好的,但如果是因为它们,请告诉我,以便我可以学习。

提前感谢所有人。


编辑#2:这是一些跟踪数据......

'o'表示传递给事件处理程序的对象

ABCService() method invoked <--
ABCService() method invoked -->

Service1() method invoked <--
Service1() method invoked -->

OnStart() method invoked <--
OnStart() method invoked -->

wellnessTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled  = False
((System.Timers.Timer) o).Interval = 5000
this.wellnessTimer.Enabled  = False
this.wellnessTimer.Interval = 5000
wellnessTimer_Elapsed() method invoked -->

invocationTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled  = False
((System.Timers.Timer) o).Interval = 30000
this.invocationTimer.Enabled  = False
this.invocationTimer.Interval = 30000
invocationTimer_Elapsed() method invoked -->

wellnessTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled  = False
((System.Timers.Timer) o).Interval = 60000
this.wellnessTimer.Enabled  = False
this.wellnessTimer.Interval = 60000
wellnessTimer_Elapsed() method invoked -->

invocationTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled  = False
((System.Timers.Timer) o).Interval = 30000
this.invocationTimer.Enabled  = False
this.invocationTimer.Interval = 30000
invocationTimer_Elapsed() method invoked -->

2 个答案:

答案 0 :(得分:1)

来自MSDN's remarks on the Timer class

  

在调用Dispose或Stop方法之后或在Enabled属性设置为false之后,可能会发生经过事件,因为提升Elapsed事件的信号始终排队等待在线程池线程上执行。解决此竞争条件的一种方法是设置一个标志,告诉事件处理程序Elapsed事件忽略后续事件。

因此,您可以在事件处理程序中执行类似的操作,以防止在计时器被禁用后执行它:

private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    if (timer.Enabled)
    {
        Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
    }
}

答案 1 :(得分:0)

您是否遇到了与您提供的代码完全相同的问题,或者它是否依赖于代码:

       // depending on logic, these next two lines will be called together or not at all

根据我从代码中读到的内容,健康计时器会在遇到onCreated调用错误时每隔60秒触发一次。如果这是在进行文件操作,那么尖叫的一件事就是服务运行的帐户的安全权限。

捕获异常时,将其输出到事件日志或日志文件。异常行为很容易导致混乱的情况,尤其是在连接调试器不太方便的情况下。