boost::condition_variable_any



  • Eine Condition-Variable die nicht mit einer Mutex zusammenarbeitet wäre keine Condition-Variable, sondern ein Event.

    Was ich mich dagegen frage ist: warum erlauben (fast?) alle Implementierungen, dass man signal() aufruft, während man die Mutex nicht gelockt hat?
    Die Forderung "bei signal() musst du die Mutex halten" würde nämlich eine recht elegante Optimierung ermöglichen - die Condition-Variable bräuchte dann nämlich intern nicht nochmal eine eigene Mutex, und man würde sich den Overhead des 2. Locks auf die interne Mutex sparen.



  • Wie macht man denn ein Signal? Ich habe nur signal-slot gefunden.
    Da es in meiner bereit() einen deadlock gab hab ich auf barrier umgestellt. Scheint mir sinnvoller zu sein:

    bool DatenModul::bereit()
    {
    
      {
        boost::unique_lock<boost::shared_mutex> lock(ModulListeMutex);
        ++bereiteModule;
      }
    
      // die Ausgabe verursacht einen deadlock mit lock, deshalb muss das oben in {}
      #ifdef DEBUG
        std::stringstream ausgabe;
        ausgabe << "Datenmodul: " << abfragenModul(boost::this_thread::get_id()) << " ist bereit. " << bereiteModule << " von "<< AnzahlModule << " Modulen sind bereit.";
        schreiben(ausgabe.str());
      #endif  
    
      if( bereiteModule==AnzahlModule)
      {
        // hier folgt nur eine Ausgabe der berieten Modul und derer Abonnenten, nicht so wichtig!
        std::stringstream ausgabe;
        ausgabe << "Datenmodul: Alle " << AnzahlModule << " Module sind bereit.\n";
        std::map< boost::thread::id, Modul* >::iterator i;
        std::map< std::string, boost::thread::id >::iterator i2;
        boost::shared_lock<boost::shared_mutex> lock2(DatenZuModulListeMutex);
        for( i=ModuleListe.begin(); i!=ModuleListe.end(); i++)
        {
          ausgabe << "  " << i->second->Modulname << " erstellt ";
    
          for( i2=DatenZuModulListe.begin(); i2!=DatenZuModulListe.end(); i2++)
          {
            if( i2->second==i->first ) ausgabe << i2->first << ". Abonennten:\n";
    
          }
        }
        schreiben(ausgabe.str());
    
      }
    
      wait();
    
      // eine Barriere die erst durchbrochen werden kann, wenn alle AnzahlModule Threads wait aufgerufen haben
      boost::barrier schranke(AnzahlModule);
    
      return true;
    }
    

    Das ganze funktioniert leider noch nicht, aber woher weiß denn wait() auf welche barrier es warten muss? Ich hab momentan nur eine, aber es könnte ja auch auf eine ganze andere warten sollen?



  • Meine Frage hat mich auch zur Lösung geführt! Man muss natürlich wait an der barrier aufrufen! Hab das nun so gelöst, dass das DatenModul ein private: boost::barrier* schranke; hat. Im Konstruktor wird diese barrier dann initialisiert:

    DatenModul::DatenModul(int i) : AnzahlModule(i)
    {
      schranke = new boost::barrier(i);
    };
    

    i ist die Anzahl an Modulen, sie wird dem DatenModul bei Konstruktion übergeben. Das Problem ist nur, das funktioniert auch nicht 😞 schreibe ich da anstatt i eine 3 rein funktioniert alles wunderbar. Nur irgendwie mag er das i nicht. Es kompiliert zwar, aber beim i kommt bei Ausführung:

    terminate called after throwing an instance of 'std::invalid_argument'
      what():  count cannot be zero.
    Aborted
    

    Kann mir das jemand erklären?



  • dann konstruierst du wohl irgendwo ein solches ding mit 0, nen?
    die einfachste erklärung ist meist die beste.

    und der debugger ist dein freund.



  • hustbaer schrieb:

    dann konstruierst du wohl irgendwo ein solches ding mit 0, nen?

    Nein, definitiv nicht! Ich ruf das Teil nur einmal in der main auf

    DatenModul* D = new DatenModul(3);
    

    Der barrier() will eigentlich size_t und ich gebe ihm einen integer. Ist das ein Problem?

    class barrier : private boost::noncopyable   // Exposition only
    {
    public:
      // construct/copy/destruct
      barrier(size_t);
      ~barrier();
    
      // waiting
      bool wait();
    };
    


  • Das ist mir jetzt peinlich. Du hattest recht, ich hab an einer anderen Stelle tatsächlich mit 0 initialisiert!
    Sorry und Danke!



  • fabske schrieb:

    Das ist mir jetzt peinlich. Du hattest recht, ich hab an einer anderen Stelle tatsächlich mit 0 initialisiert!
    Sorry und Danke!

    Hihi. Kein Problem.



  • Ich würde jetzt aber doch gerne noch wissen wie man ein Signal realisiert. Hab grad wieder die Situation, dass ein Thread warten muss bis ein anderer etwas erledigt hat. Soll ich da dann einen barrier mit zwei Teilnehmern erstellen?



  • Ich würde auch hier eine normale Condition-Variable + Mutex + bool Flag verwenden.
    Und dann "ganz normal" mit while (!flag) condition_variable.wait(lock); warten.

    Natürlich gibt es auch andere Lösungen, aber dafür z.B. eine Barrier zu verwenden, erscheint mir irgendwie komisch.



  • Ich hab nun doch eine barrier genommen und funktioniert sehr gut!

    Was ist eigentlich der Unterschied zwischen condition_variable und condition_variable_any?



  • Hallo,

    vergleiche doch die Klassen:

    http://www.boost.org/doc/libs/1_35_0/doc/html/thread/synchronization.html

    boost::condition_variable_any lässt sich mit jedem Mutex-Typen verwenden.

    MfG,

    Probe-Nutzer



  • Vielen Danke! Im Moment mache ich mir über die Destruktion von Objekten Gedanken, muss ich da bei condition_variable und barrier irgendwas beachten? Was ist wenn noch ein Thread wait() aufgerufen hat und ich diese barrier vernichte??


Anmelden zum Antworten