PostMessage() nach DestroyWindow(): Undefiniertes Verhalten?



  • @hustbaer
    Ja, und wenn ich es doch tue? UB? Oder wird es intern einfach ignoriert?

    Wieso interessiert dich das? Schreib dein Programm so, dass der Fall nicht vorkommt.

    @Martin:
    IsWindow() ist sinnlos, dann kann er genauso gleich die Message absetzen. Wenn das Handle nicht schon neu vergeben wurde, dann geht die Message ins nirvana, und es passiert einfach nix. Bzw. wird die Message nichtmal abgeschickt.
    Und WENN das Handle schon neu vergeben wurde, dann wird IsWindow() auch true melden, obwohl es schon ein ganz anderes Fenster gibt.

    IsWindow() ist IMO nur für ASSERTs brauchbar.



  • Weil ich dann im Downloadthread ne zusätzliche Abfrage brauche. Und da ich jetzt IsWindow() nicht verwenden soll, wohl irgendwie so:

    bool _abort;
    
    EnterCriticalSection(&criticalSectionAbort);
    _abort = abort;
    LeaveCriticalSection(&criticalSectionAbort);
    
    if(!_abort)
        PostMessage(dialogHandle, WM_CLOSE, 0, 0);
    

    Aber gibt es nun kein UB?


  • Mod

    @Destroy0r: Deine CriticalSection ist absolut unnötig.
    Bei Deinem Konstrukt stellt sich für mich einfach die Frage,warum ein zerstören des Hauptfensters überhaupt erlaubt ist, während der Download läuft.

    @hustbaer: Window Handles werden nicht "schnell" recycled. Das ist so weit erstmal sicher. Es gibt aber genug Race-Konditions in denen man z.B. in PreTranslateMessage, oder einem Hook etwas auslöst, was zum Beispiel andere Fenster zerstört. In diesem Moment kommt IsWindow schon zum tragen.
    Was SendMessage angeht, gebe ich Dir recht, allerdings gibt IMHO im Aplication Verifier einen Break, wenn ein Handle verwendet wird, das nciht existiert!
    Durch ein Certified for xyz würde die Anwendung dann durchfallen.



  • Ne, die ist nicht unnötig, weil "abort" im Hauptthread auf "true" gesetzt wird, und zwar bevor dort DestroyWindow() aufgerufen wird.
    Und sobald eine Variable in zwei Threads verwendet wird, muss doch synchronisiert werden.

    Und ich möchte dem User die Kontrolle lassen, wann er den Updater abbrechen will. Wenn ein Download läuft, muss der User bestimmt nicht warten, bis dieser fertig ist.
    Er wird dann zwar durch IBinding::Abort() abgebrochen, aber es könnte Folgendes passieren:

    if(!abort)
    {
        UrlDownloadToFile(...
        ...
    

    Wenn abort noch false ist, und genau danach das Fenster geschlossen wird, während also erstmal UrlDownloadToFile() beginnt, darf man noch nicht IBinding::Abort() aufrufen.
    Und wenn der Server dann hängt, hängt die Applikation.

    Deshalb werde ich wohl libcurl mit dem multiinterface verwenden, da kann immer kontrolliert abgebrochen werden.



  • Destroy0r schrieb:

    Ne, die ist nicht unnötig, weil "abort" im Hauptthread auf "true" gesetzt wird, und zwar bevor dort DestroyWindow() aufgerufen wird.
    Und sobald eine Variable in zwei Threads verwendet wird, muss doch synchronisiert werden.

    nö es ist eine atomare operation



  • @hustbaer: Window Handles werden nicht "schnell" recycled.

    Das weiss ich schon.

    Das ist so weit erstmal sicher.

    Sicher nenne ich was anderes. Sagen wir lieber es macht die Sache weniger schlimm.

    Es gibt aber genug Race-Konditions in denen man z.B. in PreTranslateMessage, oder einem Hook etwas auslöst, was zum Beispiel andere Fenster zerstört. In diesem Moment kommt IsWindow schon zum tragen.

    Jo. Deswegen ist IMO das ganze Window-Gedöns in Windows ja auch ein riesen Haufen Müll.

    Was SendMessage angeht, gebe ich Dir recht, allerdings gibt IMHO im Aplication Verifier einen Break, wenn ein Handle verwendet wird, das nciht existiert!
    Durch ein Certified for xyz würde die Anwendung dann durchfallen.

    Mag sein, ich hab noch nie eine Anwendung verifizieren lassen. Ist aber total bescheuert, weil wie gesagt das nötige "if" ja schon in SendMessage steckt.



  • @atomb0mb3
    Wie jetzt, ich muss nicht synchronisieren? Oh mann, jeder sagt was anderes. Schöne Scheisse! Wie soll man es dann richtig lernen...



  • Destroy0r schrieb:

    @atomb0mb3
    Wie jetzt, ich muss nicht synchronisieren? Oh mann, jeder sagt was anderes. Schöne Scheisse! Wie soll man es dann richtig lernen...

    du solltest es mit InterlockedExchange machen.



  • Also was nun, Synchronisation nötig oder nicht 😕



  • atomb0mb3 schrieb:

    Destroy0r schrieb:

    Ne, die ist nicht unnötig, weil "abort" im Hauptthread auf "true" gesetzt wird, und zwar bevor dort DestroyWindow() aufgerufen wird.
    Und sobald eine Variable in zwei Threads verwendet wird, muss doch synchronisiert werden.

    nö es ist eine atomare operation

    Nicht auf jeder CPU, und nicht jede Variable.
    Und generell auch nur, wenn das Alignment passt, was wiederum nicht jeder Compiler garantieren muss.

    Mal ganz davon abgesehen dass der C++ Standard diesbezüglich garkeine Garantien abgibt, weil er (noch) kein Speichermodell vorschreibt, und keine Threads kennt.



  • Alles klar, dann synchronisiere ich.
    Soll ich dann InterlockedExchange() für eine reine Abfrage so verwenden?

    if(InterlockedExchange(&abort, abort))
        ...
    


  • ist nicht notwendig, wie martin richter schon sagte



  • @PullePepe
    Du meinst damit jetzt die Abfrage auf ein totes Fenster?



  • Destroy0r schrieb:

    @PullePepe
    Du meinst damit jetzt die Abfrage auf ein totes Fenster?

    Nein, der Aufruf von InterlockedExchange oder EnterCriticalSection. Das brauchst du nur bei Anwendungen, die speziell auf Mehrprozessorsysteme zugeschnitten sind.


  • Mod

    Für rein Flag vom Typ bool oder Integer ist höchstens das Keywort volatile notwendig. Weder InterlockExchange noch CriticalSection. Warum auch?


  • Mod

    hustbaer schrieb:

    Was SendMessage angeht, gebe ich Dir recht, allerdings gibt IMHO im Aplication Verifier einen Break, wenn ein Handle verwendet wird, das nciht existiert!
    Durch ein Certified for xyz würde die Anwendung dann durchfallen.

    Mag sein, ich hab noch nie eine Anwendung verifizieren lassen. Ist aber total bescheuert, weil wie gesagt das nötige "if" ja schon in SendMessage steckt.

    Nein tut es nicht. Wenn z.B. Hooks installiert werden oder OLE läuft (STA läuft über die Message Queue) dann greifen intern Mechanismen, die es z.T. nicht mögen, dass Nachrichten an Fenster gesandt werden, die 1. Nicht existieren oder 2. nicht mehr existieren.



  • Höchstens volatile. Und wann?
    Ich dachte, man muss einen Zugriff aus mehreren Threads synchronisieren.
    So wie ich @hustbaer verstanden habe, sollte ich synchronisieren.


  • Mod

    hustbaer hat nichts dergleichen gesagt...

    Du hast ein Flag abort. Das soll geprüft werden...
    Wenn es gesetzt ist Abbruch, wenn nicht ein neuer Schleifendurchlauf?
    Was soll hier eine Schutz der Variable?
    Was denkst Du denn was anders wird?

    CriticalSection müssen verwendet werden wenn Wertepaare/gruppen maipuliert werden.

    volatile sagt dem Compiler, dass diese Variable, von extern (anderer Thread) geändert werden kann. Der Compiler darf also diese Variable nicht optimieren.



  • Destroy0r schrieb:

    Höchstens volatile. Und wann?
    Ich dachte, man muss einen Zugriff aus mehreren Threads synchronisieren.
    So wie ich @hustbaer verstanden habe, sollte ich synchronisieren.

    Du musst den Zugriff durch eine Mutex oder eine Semaphore synchronisieren. Was Martin meinte gilt nur für gemeinsamen Lesezugriff. Bei gemeinsamen Schreibzugriff muss die Synchronisation erfolgen, da sonst Inkonsistenzen entstehen können, da ja auf Assemblerebene die Variable zuerst in ein Prozessorregister gelesen werden muss, es also keine atomare Operation ist, sondern 3 oder mehr Maschinenbefehle.



  • hustbaer schrieb:

    atomb0mb3 schrieb:

    Destroy0r schrieb:

    Ne, die ist nicht unnötig, weil "abort" im Hauptthread auf "true" gesetzt wird, und zwar bevor dort DestroyWindow() aufgerufen wird.
    Und sobald eine Variable in zwei Threads verwendet wird, muss doch synchronisiert werden.

    nö es ist eine atomare operation

    Nicht auf jeder CPU, und nicht jede Variable.
    Und generell auch nur, wenn das Alignment passt, was wiederum nicht jeder Compiler garantieren muss.

    Mal ganz davon abgesehen dass der C++ Standard diesbezüglich garkeine Garantien abgibt, weil er (noch) kein Speichermodell vorschreibt, und keine Threads kennt.

    Oh Mann! *VERWIRRUNG*

    Ein reiner Lesezugriff muss nicht synchronisiert werden? Ich hab mich zwar auch immer gewundert, warum es so sein sollte, allerdings las ich bis jetzt immer, dass man auch da synchronisieren muss!

    Nun, in meinem Fall gibt es aber auch einen Schreibzugriff.

    @Martin Richter
    Das Flag kann im Hauptthread auf true gesetzt werden. Im Downloadthread wird es eigentlich nur abgefragt.

    Und nun? Brauche ich nun eine Synchronisation?

    Was meinst du mit Wertepaare/gruppen?

    Martin Richter schrieb:

    Für rein Flag vom Typ bool oder Integer ist höchstens das Keywort volatile notwendig. Weder InterlockExchange noch CriticalSection. Warum auch?

    Lies was @hustbaer geschrieben hat. Demnach ist das Schreiben/Lesen eines bool/int nicht zwingend atomar, also muss ich es doch synchronisieren?

    Ich verzweifle...


Anmelden zum Antworten