Was macht Application.DoEvents() ?



  • Hallo an alle,

    ich sitze an einem relativ großen Projekt(WinForms), welches in C++/Cli programmiert wurde.
    In diesem Projekt wird unter anderem auch mit extra Threads und dem Threadpool gearbeitet.

    Leider kommt es häufig vor, das in einem neu erstelllten Thread ab und an "Application::DoEvents()" aufgerufen wird. Nun müsste ich GENAU wissen was dann im Hintergrund abläuft, da ich vermute das sich einige Bugs daraus ergeben.

    Ich weiß das der Einsatz von "DoEvents" absoluter Mist ist, und es nach Refactoring/Designproblemen schreit. Leider hat sich bisher nie jemand darum gekümmert und man(ich) soll auf die schnelle einige Bugs beheben.

    Also was ich weiß bzw vermute:
    Jedes WinForm-Application besitzt einen Thread zu dem alle "GUI-Objekte / Controls" gehören. Nur innerhalb dieses Threads darf auf diese Objekte zugegriffen werden (Update/Redraw/...). Dieser Thread (ich nenne ihn ab hier GUI-Thread) arbeitet nach bestimmten Zeitabständen die Messages in der Message-Queue ab.

    Ein Aufruf von Application::DoEvents() stoppt den aktuellen Programmablauf, und arbeitet alle aufgelaufenen Messages in der Message Queue ab. Was passiert allerdings wenn dieser Aufruf in einen anderen Thread gemacht wurde? (Thread "Worker").

    Stoppt der aktuelle Programmablauf im "Worker", wechselt zum GUI-Thread und arbeitet dort alle Messages in der Message Queue ab? Und wechselt danach wieder zum Worker zurück und macht an dieser Stelle weiter? Oder werden die Messages im Kontext des Worker-Threads abgearbeitet?

    Laut MSDN-Doku wird der aktuelle Thread Suspended und die Message Queue abgearbeitet. Allerdings finde ich keine verlässliche Aussage was sonst noch alles passiert, bzw finde ich dass das etwas (zuviel) Interpretationsfreiheit bietet.

    Kann jemand verlässliche Aussagen darüber treffen, bzw hat verlässliche Quellen zur Hand?

    Besten Dank im Vorraus,

    Gruß



  • Ich bin etwas überrascht, dass man das aus Seitenthreads aufrufen kann. Ich vermute, es wird nichts machen.
    Außer vielleicht, es hängt mit COM und STA zusammen, aber da weiß ich zu wenig darüber, wie das in .NET implementiert ist. Glaubs jetzt aber auch nicht, macht wahrscheinlich einfach keinen Sinn.



  • Jedes WinForm-Application besitzt einen Thread zu dem alle "GUI-Objekte / Controls" gehören.

    Nö. Es kann mehrere GUI Threads geben. Jedes Fenster gehört aber zu genau einem GUI Thread, nämlich zu dem GUI Thread der es erzeugt hat (*).

    Ein Aufruf von Application::DoEvents() stoppt den aktuellen Programmablauf, und arbeitet alle aufgelaufenen Messages in der Message Queue ab. Was passiert allerdings wenn dieser Aufruf in einen anderen Thread gemacht wurde? (Thread "Worker").

    Soweit ich weiss arbeitet Application.DoEvents nur die Messages ab die zu Fenstern gehören die vom aktuellen Thread erzeugt wurden. Das würde zumindest dem Verhalten das man von Win32 gewohnt ist entsprechen.

    Das "gefährliche" an DoEvents ist:

    MSDN schrieb:

    If a message causes an event to be triggered, then other areas of your application code may execute. This can cause your application to exhibit unexpected behaviors that are difficult to debug.

    Was passiert wenn man DoEvents in einem "nicht-GUI" Thread aufruft, weiss ich nicht. Vermutlich nichts (**). Lässt sich aber ziemlich einfach ausprobieren -- also zumindest ob es direkt in einer Exception endet.

    *: Etwas vereinfacht, aber die genauen Regeln z.B. bezüglich AttachThreadInput & Co kenne ich auch nicht. AttachThreadInput & Co werden aber auch nicht oft verwendet.

    **: Was vermutlich schon passiert: Es wird eine Message Queue für den aufrufenden Thread erzeugt werden. Vermutlich wie gessagt. Was das genau für Folgen hat kann ich dir auch nicht sagen. Vermutlich keine die in deinem Programm eine Rolle spielen. 🙂



  • @Mechanics
    Wieso sollte man das nicht aus beliebigen Threads aufrufen können?
    Unter Win32 kannst du auch in jedem beliebigen Thread nen PeekMessage/DispatchMessage Loop machen.



  • @hustbaer: naja, bin ja nur "etwas" überrascht 😉 Ich hätte eher erwartet, dass .NET merkt, dass der aktuelle Thread kein GUI Thread ist und eine Exception schmeißt. So ungefähr, wie beim Zugriff auf Controls aus Nebenthreads. Aber hab das noch nie ausprobiert (kann mich eh nicht dran erinnern, jemals Application.DoEvents verwendet zu haben).


Anmelden zum Antworten