WaitForSingleObject und Threads



  • Hallo,

    darf ich folgendes Szenario implementieren:

    Ein Thread wartet durch WaitForSingleObject auf einen Trigger.
    Das Hauptprogramm Triggert mit SetEvent
    Es gibt von dem Thread mehrere Instanzen ( die ggf. gleichzeitig warten)

    geht das?



  • Grundsätzlich: ja, sowas geht.

    Etwas spezieller: Events sind doof.
    Was ganz gut geht, ist wenn man immer nur einen Thread aufwecken will, und auch nicht will dass 2 Threads aufwachen wenn 2x getriggert wurde während kein Thread gewartet hat.
    Dann kann man Auto-Reset Events verwenden.

    Was auch gut geht ist wenn man nur einen Thread hat der wartet.

    Alles andere ist mit Events nur umständlich zu lösen. Condition-Variablen eignen sich da viel besser. Unter Windows gibt's die "native" ab Vista. Ansonsten gibt's Libraries wie Boost oder neuerdings auch die C++ Standard Library die Condition-Variable Implementierungen anbieten.



  • OK, danke für die (Nachricht) dass es grundsätzlich geht, aber doof ist. 🙂

    In meinem Fall ist es sogar erwünscht dass alle Threads aufwachen. Dann bin ich ja da am richtigen Ansatz, oder?
    Muss ich noch irgendwas beachten?

    Leider bin ich an den BCB2007 gebunden, der wird die Condition-Variablen sicher nicht kennen.



  • Wenn du "aktuelle" Windows SDKs (also >= Vista) verwenden kannst, dann muss das auch mit nem alten Bo(h)rland gehen:
    http://msdn.microsoft.com/en-us/library/windows/desktop/ms682052(v=vs.85).aspx

    > In meinem Fall ist es sogar erwünscht dass alle Threads aufwachen. Dann bin ich ja da am richtigen Ansatz, oder?
    Möglicherweise, möglicherweise auch nicht.

    > Muss ich noch irgendwas beachten?
    Ja, beschreib mal deinen Anwendungsfall etwas genauer.



  • Ich hab WaitForMultipleObjects (sollte keinen Unterschied machen) mit vielen threads benutzt um diese z.B. mitten im Ablauf zu beenden falls der user es so mag.
    Funktioniert hervorragend.
    Du musst die threads in dem Fall nur sich selber ordentlch beenden lassen.


  • Mod

    Wenn Du keinen Auto Reset Event nimmst must Du nur wissen wann Du kontrolliert wieder das Event zurücksetzt.

    Es könnte ja sein, dass ale Threads ganz flink mit dre Arbeit fertig sind und das Event schon (oder immer noch) als gesetzt finden und weiter laufen...



  • Martin Richter schrieb:

    Wenn Du keinen Auto Reset Event nimmst must Du nur wissen wann Du kontrolliert wieder das Event zurücksetzt.

    Es könnte ja sein, dass ale Threads ganz flink mit dre Arbeit fertig sind und das Event schon (oder immer noch) als gesetzt finden und weiter laufen...

    Hab es mir von flounder abgekuckt. 😉

    Irgendwo resette ich das schon. Finde es aber im Moment nicht weil ich müde bin.

    EDIT:
    Wenn die threads den event kriegen beenden sie ich alle brav.
    Der event betrifft eigentlich nur das Abbrechen von internet-verbindungen und da sollte ein einzelner thread nicht den event zurücksetzen dürfen/können.

    Das passiert dann eine Ebene höher. Also bei meinem Kumpel, der wo richtig Ahnung hat und der ist, der die ganzen threads verwaltet. 😉



  • Dann sollte dir dein Kumpel eine CancelFlag klasse implementieren, sowas in der Art:

    class CancelFlag : noncopyable
    {
    public:
        bool IsCanceled() const;
        bool Wait(DWORD timeout) const;
    
        // ...
    };
    

    Und dir einfach eine CancelFlag Instanz mitgeben.
    Dann musst du dich nicht darum kümmern wie das intern alles funktioniert. Und er kann es dank Kapselung genau kontrollieren - weil du keinen Zugriff auf Implementierungsdetails wie z.B. den Event hast.


  • Mod

    Jo. Für einen simplen Status benötigt man kein Event.



  • EDIT:
    Ohne (non graceful) shutdown + closesocket kracht es irgendwann erfahrungsgemäß.
    Ich muß ja erst den socket schließen bevor der thread sich beenden darf.



  • Ich find' die "auf Event warten" Sache eh OK. Ich würde es nur wie gesagt in einer eigenen Klasse wegkapseln.



  • Für Vorschläge wäre ich dankbar.
    Im Moment sieht es so aus:

    IMPLEMENT_DYNCREATE(CDownloadThread, CWinThread)
    

    und dann in CDownloadThread

    void SetStopEvent( HANDLE se ) { StopEvent = se; };
    

    - setzt mein Kumpel von oben, der nen Plan hat. 😉
    und dann im thread

    if( ::WaitForSingleObject( StopEvent, 0) != WAIT_OBJECT_0 )
    

    else kehrt er zurück nach oben und bekommt dann sehr wahrscheinlich

    if (!::PostThreadMessage(m_ThreadArray[i].threadID, UWM_TERM_THREAD, 0, 0))
    

    Danach wird aufgeräumt und thread begeht "Selbstmord" und meldet diesen etwa so

    if( !target->PostMessage(UWM_THREADCLOSE, (WPARAM) m_test_thread, (LPARAM)m_nThreadID) )
    

    in

    int CDownloadThread::ExitInstance()
    

    An den Variablennamen bitte nicht aufregen, sind teilweise einfach von flounder kopiert.


Log in to reply