Mit einem timer in einem Windows-Dienst - elapsed-Ereignis-handler hält brennen noch, wenn der timer deaktiviert ist

Ich habe viel gelesen von den Beiträgen im Zusammenhang mit Windows-Diensten und die Verwendung von Timern, aber ich habe nicht gefunden, einen Grund, warum meine event-handler wird trotzdem ausgelöst werden kann. Kann jemand mich in die richtige Richtung? Ich will wissen warum das ist geschehen, damit ich verstehe, wie dies zu vermeiden in der Zukunft.

Edit: Das onError-event-handler wird nie aufgerufen (oder ich gesehen haben, das Ereignis in die Ereignis-log).

Timer: System.Timer.Timer

ServiceBase: System.ServiceProcess.ServiceBase


Hier ist die abstrakte Klasse:

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();
    }
}

Hier ist eine Instanz der Klasse:

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();
            }
        }
    }
}

Hier ist der automatisch generierte code für die partielle Klasse:

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
}

Also, was genau ist passiert? Ich freu mich auf mein event-log und ich sehe, dass einmal pro minute die wellnessTimer event-handler aufgerufen wird.

Hier ist, was ich denke passiert, aber ich bin offensichtlich falsch:

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

Zu diesem Zeitpunkt beide Timer sollte noch vorhanden sein, damit diese Instanz, die aber deaktiviert werden sollten. Ich gedebuggt dieses über attach to process in Visual Studio 2010 und markiert eine ID für das Objekt (sender) übergeben wird in die event-Handler. Es ist das gleiche Objekt wie die Instanz. Auch die beiden Timer in den Fenster hatte, deren enabled-Eigenschaft auf false festgelegt.

Macht mich das, was ich bin mit der Vererbung falsch, oder was ist Los mit threading. Ich bin nicht der beste in diesen Sachen, aber wenn es wegen Ihnen bitte lassen Sie mich wissen, damit ich lernen kann.

Danke an alle im Voraus.


Edit #2: Hier einige Daten zu verfolgen...

'o' steht für das übergebene Objekt in den event-handler

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 -->
Versuchen Sie zu kommentieren wellnessTimer.Start() auf die onError-Methode. Vielleicht (nur vielleicht) etwas schief gehen, und das error-Ereignis wird ausgelöst?
Die richtige Richtung ist hier.
Sie können versuchen, die aufrufende Timer.Dispose()
Aye, ich habe gelesen, dass auch. Aber ich werde mit Ihnen einverstanden. Diese Anwendung wurde entwickelt, um kontinuierlich laufen; der Timer sollte nicht brennen, die auf einem vorbestimmten Intervallen.
Ich aktualisierte mein code entsprechend der Ereignis-Protokollierung. Die onError-event-handler wird nie aufgerufen.

InformationsquelleAutor The Cog | 2012-07-24

Schreibe einen Kommentar