Windows.Forms.Timer läuft in separatem Thread ?!

  • C#
  • .NET (FX) 1.0–2.0

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von TRiViUM.

    Windows.Forms.Timer läuft in separatem Thread ?!

    Guten Morgen liebe Community,

    ich habe gerade ein merkwürdiges Verhalten des System.Windows.Forms.Timer festgestellt und würde gern wissen, wie das zu verstehen ist.

    Ganz simpler Test-Aufbau:
    Der MainDialog ruft einen Dialog auf, wo sich ein Timer als Component und ein Timer als Nicht-Component drin befindet.
    Beide sind Enabled = true und haben einen Interval von 1000ms.
    Jeder Timer schreibt in seinem Tick-Event eine Zeile mit einem Zähler in das Ausgabe-Fenster (Console.WriteLine).

    Wird nun das Form, in dem sich der Timer befindet, geschlossen, bleibt der Component-Timer stehen, jedoch der Nicht-Component-Timer nicht!
    Dass der Component-Timer nicht mehr weiter zum Tick-Event kommt, kann ich noch verstehen (Auszug aus dem Designer-Code):

    C#-Quellcode

    1. /// <summary>
    2. /// Clean up any resources being used.
    3. /// </summary>
    4. /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    5. protected override void Dispose(bool disposing)
    6. {
    7. if (disposing && ( components != null ))
    8. {
    9. components.Dispose();
    10. }
    11. base.Dispose( disposing );
    12. }


    Was ich aber nicht verstehe ist, dass ich das Form, wo sich der Timer drin befindet, in einem Using-Statement aufrufe verwende, welches auch durchläuft (Objekt sollte also disposed sein).
    Wieso läuft hier der Nicht-Component-Timer dennoch weiter, obwohl das Form, wo er sich drin befindet, eigentlich disposed wurde?

    Ich habe das Beispiel-Projekt angehangen...

    Danke für Eure Infos :saint:
    Dateien
    • TimerExample.zip

      (13,24 kB, 38 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „TRiViUM“ ()

    Spekulatius: Weil zwar das Form disposed wird (und damit seine Komponenten, in denen eben Timer1 drinsteckt), aber nicht die Nichtkomponente timer. Daher wird der GC wahrscheinlich denken: »Oh, der wird wohl noch gebraucht, dann werd ich den mal lieber nicht entsorgen.« Schließlich ist ja noch ein EventHandler mit timer verknüpft. Deswegen gehört zu jeder selbst eingebauten Event-EventHandler-Verdrahtung ein Durchschneiden der Verbindung am Ende des Programmteils (in VB.NET: mittels RemoveHandler)

    btw: Natürlich gehört timer auch in die Kategorie "Komponente", aber solange die nicht bei den components von form2 "registriert" ist, wird form2 timer auch nicht automatisch stoppen/disposen/entsorgen (können).
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    VaporiZed schrieb:

    Schließlich ist ja noch ein EventHandler mit timer verknüpft
    Knapp, aber das ist nicht der Grund, warum der Timer stehen bleibt. Ein Event hält kein Objekt am Leben, wenn sich beide Seiten, also der Sender und der Empfänger nicht mehr als Referenz irgendwo halten. Abgeschlossene loops werden vom GC auch aufgeräumt.

    Es liegt hier da dran, dass der Timer sich im Enabled ein Handle vom GC holt.

    C#-Quellcode

    1. ​timerRoot = GCHandle.Alloc(this);

    Timer.cs

    Dadurch weiß der GC, dass er diese Objekt nicht aufräumen darf, bis das Handle wieder freigegeben wurde, selbst wenn das Handle verloren geht.




    Der Timer bleibt also stehen bis er Disposed oder Disabled wird.
    Ich musste es 3x lesen, bis ich zu dem Schluss kam: "Der Timer bleibt stehen" = "der Timer existiert weiter" und nicht: "der Timer feuert keine Events mehr" (im Sinne von die Uhr bleibt stehen und gibt keine Zeitupdates mehr).
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Bluespide schrieb:

    Es liegt hier da dran, dass der Timer sich im Enabled ein Handle vom GC holt

    Soweit habe ich gar nicht über den Tellerrand geschaut. Ich dachte viel mehr, dass ich das irgendwie verbockt habe, dass er im Hintergrund weiterläuft...

    VaporiZed schrieb:

    Ich musste es 3x lesen

    Dito :D

    Danke für die Erklärungen :thumbup:

    TRiViUM schrieb:

    Was ich aber nicht verstehe ist, dass ich den Timer-Dialog in einem Using-Statement aufrufe, welches auch durchläuft (Handle sollte also zerstört sein).
    Daraufhin habich deinen Code durchsucht - nichts dergleichen gefunden.

    Gfallt mir nicht so recht, dass du Behauptungen aufstellst, die nicht stimmen, die aber Leuts wie mich grundlos in ihrem Weltbild erschütterrn.
    (Weil in meiner Welt feuert eine disposete Componente keine Events mehr, und wenn ein Using-Block durchlaufen ist, dann ist disposed.
    (Darüberhinaus ist unklar, was bei dir ein Timer-Dialog ist - aber offsichtlich ist das etwas anderes als ein Timer))
    Die beiden Timer werden in form2 erzeugt und die form2-Instanz wird per using-Block erzeugt. Da der weiterlaufende Timer aber eben nicht bei den form-components registriert wird, wird er auch nicht disposed. Er schrieb nicht, dass er den Timer mittels eines using-Blocks erzeugt, sondern in einem using-Block (nämlich den von form2) aufruft, was formal auch richtig ist, da dessen Existenz mit der von der form2-Instanz einhergeht. Ja, kleinlich gesehen wird da auch nix "aufgerufen", sondern nur verwendet.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @ErfinderDesRades
    Zugegeben, die Formulierung mit dem Timer-Dialog ist blöd gewählt. Hab's jetzt in das Form, in dem sich der Timer befindet geändert.
    Und die Formulierung mit dem Using ist in meinen Augen, bis auf das aufgerufen -> verwendet richtig - @VaporiZed hat es dann quasi noch mal ausformuliert.

    Aber dennoch: Verzeihung, wenn meine Formulierung dich älter werden lies :whistling: