Aus System.Timers.Timer_Elapsed Ereignis soll der Hauptthread informiert werden

mage

Erfahrenes Mitglied
Hallo,

ich implementiere gerade einen kleinen Windowsdienst. Im Dienst verwende ich das Timer objekt aus System.Timers. Dort sollen bestimmte Arbeiten ausgelöst werden.
Mein Problem ist das Standardmäßig das Timers_Elapsed Ereignis aus einem anderen Threadkontext aufgerufen wird. Die Abarbeitung soll im Hauptthread durchgeführt werden.
Ich würde also gern aus dem Timers_Elapsed Ereignis meinen Hauptthread benachrichtigen. Wie stellt man so etwas an?
Ich weiss das ich dem Timer ein Synchronisierungsobjekt zuweisen kann, in dessen Kontext die Ereignisbehandlung durchgeführt wird. Dazu müsste ich dann allerdings die ISynchronizeInvoke Schnittstelle implementieren, da ich ein eigenes Objekt habe welche die Schnittstelle nicht standardmässig besitzt. Leider weiss ich nicht wie das funktioniert, noch habe ich ein Beispiel dazugefunden.
Anmerkung - es geht hier nicht um Steuerelemente(Controls).
Ich hoffe es weiss jemand Rat oder gute Quellen :).
 
Hi!

Hast Dir schonmal die ISynchronizeInvoke Implementation im Reflector angeschaut? Vielleicht lässt die sich ja auch auf deine Objekte anwenden, sofern möglich. Selber habe ich das noch nicht versucht.

Wenn der Aufwand aber den Nutzen übersteigt, würde ich die Ereignisparameter in einen synchronisierten Queue schieben und diesen von deinem MainThread abarbeiten lassen, bis dein WorkerThread fertig ist.

Oder Du synchronisierst alle Zugriffe in dem Event über das Objekt, welches alle Objekte hält, die in der Ereignisbehandlung angesprochen werden.
 
Mit dem Reflector zu schauen ist eine gute Idee.

Problem an der Stelle ist leider das der neue Thread vom Timerobjekt verwalten bzw. instanziert wird. Ich schaffe es ja nicht mal meinen Hauptthread zu informieren, geschweige den ich weiss überhaupt nicht direkt in welchem Thread ich mich befinde.
Ich hab schon versucht mir ein Delegate zu definieren und diesen dann im TimerElapsedEreignis zu invoken. Leider wird der Delegate nicht im Kontext des Hauptthreads ausgeführt.

Mal meine Klasse auf das wesentliche zusammengekürzt..
Code:
...
    Private Delegate Sub TimerElapsedDelegate()
    
    Private _TimerElapsedDeleg As TimerElapsedDelegate
    Private WithEvents _Timer As New System.Timers.Timer


    Private Function StartTimer() As Boolean
        _TimerElapsedDeleg = New TimerElapsedDelegate(AddressOf Me.OnTimer_Elapsed)
        Call _Timer.Start()
     ...
     End Function

     ' Wird vom Timer in einem anderen Thread ausgeführt
     Private Sub _Timer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _Timer.Elapsed
        ' Methode im Hauptthread ausführen
        Me._TimerElapsedDeleg.Invoke()
    End Sub

   '  Methode soll im Kontext des Hauptthreads ausgeführt werden
    Private Sub OnTimer_Elapsed()
        RaiseEvent TimerElapsed("Timer Tick: " & DateTime.Now.ToString("dd.MM.yyyy hh:mm:ss"))
    End Sub
 
Währe es nicht erst mal ausreichend, wenn Du die gesamte Ereignisbehandlung mit Monitor.Enter und Monitor.Exit synchronisierst? Oder passiert einfach noch zu viel in deinem HauptThread, so dass es dessen Ablauf empfindlich stören würde?

Und was spricht gegen einen einfachen Timer in deinem HauptThread, der die Ereignisdaten zyklisch aus einem synchronisierten Queue abgreift und verwertet?

Was aber auch möglich währe, ist einfach von Control zu erben und somit die ISynchronizeInvoke Implementation nicht selber implementieren zu müssen.
 
Was meinst du mit einem einfachen Timer im Hauptthread?
Der Timer im Hauptthread ist ja eigentlich einfach bzw. soll es sein. Es ist nicht notwendig das mein Dienst Multithreading ist. Ich bekomm es nur leider nicht verhindert, dass das TimerElapsed Ereignis im selben Thread ausgeführt wird, sondern schon von Haus aus in einem neuen Thread.
Ich bekomme es leider nicht hin meinem Hauptthread eine einfache Benachrichtigung zukommen zu lassen.
 
Wenn es nicht notwendig ist, dass dein Dienst mit Multithreading arbeitet, benötigst logischer Weise auch keinen Timers.Timer. Also keinen extra Thread in dem der Vorgang ausgeführt werden soll. Daher kannst auch den einfachen Forms.Timer verwenden.

Mit einfachen Timer im Hauptthread meinte ich eben einen simplen Timer, der die Ereignisdaten von dem WorkerThread verarbeitet. Der WorkerThread schiebt Objekte mit den Ereignisdaten in einen synchronisierten Queue und der Timer im HauptThread greift die Ereignisdaten ab. Das währe eine Alternative, wenn man keine Möglichkeit zum invoken hat.
Schau mal in folgenden Post: [post=1030481]Re: Threading hilfe - Post[/post]. In dem C# Worker Thread Starter Kit findest ein sehr nettes Beispiel für einen synchronisierten Queue.
 
Danke, das mit dem System.Windows.Forms.Timer hat funktioniert.
Es bleibt alles im gleichen Thread.

Auf Multithreading kann ich in diesem Projekt verzichten, da eine sequenzielle Abarbeitung notwendig ist.
 

Neue Beiträge

Zurück