1

我已经阅读了很多与 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 窗口中的两个计时器都将其启用属性设置为 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 -->
4

2 回答 2

1

MSDN 对 Timer 类的评论

Elapsed 事件可能在调用 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);
    }
}
于 2012-07-24T01:11:01.697 回答
0

您是否遇到与您提供的代码完全相同的问题,还是取决于周围的代码:

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

根据我从代码中读到的内容,当在 onCreated 调用中遇到错误时,健康计时器将每 60 秒触发一次。如果这是在执行文件操作,那么需要注意的一件事是运行该服务的帐户的安全权限。

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

于 2012-07-24T01:21:03.113 回答