Boost Threads - Programm schläft ein bei Konsolen minimierung



  • hustbaer schrieb:

    WAR][FIRE schrieb:

    Ich weiß nicht wie es passieren kann, dass ein Thread der schon ewig wartet, keinen Zugriff auf einen mutex bekommt, obwohl im anderen Thread regelmäßig der Bereich freigegeben wird und danach eine Rechenaufgabe durchgeführt wird...

    Wenn die "Mutex" zufälligerweise eine CRITICAL_SECTION ist, dann ist das IIRC sogar dokumentiertes verhalten.

    Wie dem auch sei. Ich habe den blockierenden Thread mit einem 5 ms wait ausgebremmst, so das die anderen auch mal dürfen.

    Sehr unsaubere "Lösung".

    Hallo hustbaer,

    ich weiß 😞 aber ich bin schonmal froh das ich eine Lösung zum Präsentieren haben. :p

    Hast du evtl. eine schönere Lösung?

    Am besten wären Prioritätsvergaben für mutex.

    Sowas wie:

    mutex.lock(prio_low);
    

    Wenn es sowas geben sollte.

    Gruß
    WAR][FIRE



  • WAR][FIRE schrieb:

    Ich warte bis eine Variable einen bestimmten Wert annimmt. Gibt es in Boost zufällig Semaphoren?

    http://www.boost.org/doc/libs/1_40_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref Gibt sogar ein Codebeispiel 🙂

    EDIT: selbstgebaute Mutexe aus reinen bools koennen sehr hart ins Auge gehen! Stell den Code mal um, so dass du Conditional Variables verwendest. Wuerd mich nicht wundern wenn sich dein Problem damit aufloest 🙂

    EDIT2: wobei ich das Codebeispiel in der Boost-Doku nicht ganz korrekt finde. IMHO muesste die bool-Variable "volatile" sein, damit der Compiler nicht in Versuchung kommt, den Zugriff darauf in der while-Schleife wegzuoptimieren. Kann mir das wer mit mehr Ahnung bestaetigen?



  • Dieses Beispiel?

    boost::condition_variable cond;
    boost::mutex mut;
    bool data_ready;
    
    void process_data();
    
    void wait_for_data_to_process()
    {
        boost::unique_lock<boost::mutex> lock(mut);
        while(!data_ready)
        {
            cond.wait(lock);
        }
        process_data();
    }
    

    Da kann ich dir bestätigen dass deine Vermutung falsch ist.
    Der Aufruf von cond.wait(lock) verhindert hier effektiv, dass der Compiler den Wert von data_ready in einem Register behält, oder sogar den Zugriff ganz wegoptimiert.
    volatile ist also nicht nötig.



  • WAR][FIRE schrieb:

    Hast du evtl. eine schönere Lösung?

    Vermutlich hätte ich eine schönere Lösung, wenn ich etwas genauer wüsste, was du da eigentlich machen willst.
    Kannst du ein kleines Beispiel posten? Aber bitte nicht 2-3 Zeilen, sondern so dass alles relevante drinnen ist, dass man erkennen kann wozu dieses etwas seltsame lock/unlock Muster gedacht ist etc.

    Oder du beschreibst das was du eigentlich machen wolltest. Also was "was", und nicht das "wie".


  • Mod

    Blue-Tiger schrieb:

    EDIT2: wobei ich das Codebeispiel in der Boost-Doku nicht ganz korrekt finde. IMHO muesste die bool-Variable "volatile" sein, damit der Compiler nicht in Versuchung kommt, den Zugriff darauf in der while-Schleife wegzuoptimieren. Kann mir das wer mit mehr Ahnung bestaetigen?

    volatile ist weder notwendig noch würde es im schlimmsten Fall helfen.
    Solange der Compiler nicht beweisen kann, dass data_ready aliasfrei ist (bei Objekten mit extern linkage müsste man das gesamte Programm analysieren), oder er den gesamten Code in cond.wait kennt (praktisch ausgeschlossen, hier sind an irgendeiner Stelle immer Assemblerroutinen oder Systemaufrufe im Spiel), muss er davon ausgehen, dass der Aufruf cond.wait(look) den Zustand von data_ready möglicherweise verändert. Hier die Abfrage wegzuoptimieren genügt dann aber der as-if-Regel nicht mehr.
    Umgekehrt nützt volatile dann auch nichts, wenn die Abfrage ohne wegoptimiert würde. volatile hat an dieser Stelle nichts verloren - in den Fällen, in denen es zu helfen scheint, fehlt in der Regel eine Schreib-/Lesebarriere.



  • Gerne:

    Was wird gemacht:

    Es wird ein Industrieroboter angesteuert, der einen permanenten Kommunikationsaustausch fordert. Deswegen musste ein Thread erstellt werden, der dies realisiert.

    Weiter müssen dem Roboter Befehle mitgeteilt werden. Diese Befehle müssen in die Kommunikationsschleife eingebracht werden.

    Daher: Eine Methode muss in den Thread eingreifen und Befehlsdaten übermitteln.

    Dafür wurden mutexe eingesetzt:

    //Das ist der Kommunikationtionsthread, der permanent sendet und empfängt.
    //Hier war das Problem, dass bei einem unlock() direkt wieder ein lock() 
    //ansteht. Das hat die Methode nicht zugreifen lassen bzw. schon, wenn die 
    //Konsole im Vordergrund war?!?!?!?
    foo::thread()
    {
         while(true)
         {
              mutex.lock();
    
              senden(daten);
    
              empfangen(...)
    
              mutex.unlock();
              wait(5); //Dieses wait() löst das Problem (unsauber)
         }
    }
    
    foo::methode()//Diese Methode muss Daten (Befehle) in den Kommunikationsthread einbringen 
    {
         mutex.lock();
         daten = 5;
         mutex.unlock();
    }
    

    Der Kommunikationsthread arbeitet mit den "daten". Daher müssen diese synchronisiert werden.

    Ja ich hoffe das macht das Problem deutlich. Wäre gut wenn es dafür eine saubere Lösung gibt. Waits gefallen mir auch nicht wirklich.

    Gruß
    WAR][FIRE



  • naja man könnte es zum bleistift so machen:

    foo::thread() 
    { 
         mutex.lock(); 
         while(true) 
         { 
              TYP lokale_kopie = daten;
              mutex.unlock(); 
    
              senden(lokale_kopie); 
              TYP2 e = empfangen();
    
              mutex.lock(); 
              trallala = e;
         } 
         mutex.unlock(); 
    } 
    
    foo::methode()//Diese Methode muss Daten (Befehle) in den Kommunikationsthread einbringen 
    { 
         mutex.lock(); 
         daten = 5; 
         mutex.unlock(); 
    }
    

    sollte das aus irgendeinem grund nicht gehen, schreib bitte ein beispiel bzw. eine erklärung die ausreichend ist, um zu verstehen, wieso es nicht geht 🙂



  • camper schrieb:

    Solange der Compiler nicht beweisen kann, dass data_ready aliasfrei ist (bei Objekten mit extern linkage müsste man das gesamte Programm analysieren), ...

    ... und bei Objekten mit internal linkage bzw. sogar lokalen Variablen, gibt es nur zwei Möglichkeiten:

    a) entweder der Thread hat überhaupt garkeine Möglichkeit die Variable zu modifizieren (weil er die Adresse nicht kennt), oder
    b) die Adresse der Variable muss irgendwo "an den Thread übergeben" worden sein

    a) ist ja kein Problem, und im Fall b) muss der Compiler zu dem Schluss kommen, dass ein Alias auf die Variable existieren könnte.



  • @hustbaer & camper: thx fuer die Aufklaerung 🙂



  • Danke huste hustbaer!

    Wurde so umgesetzt 🙂

    Gruß
    WAR][FIRE


Anmelden zum Antworten