//Brainbug-kl. Kopfnuss - Thread Synchroniserung



  • Hallo @All
    Hab gestern eine alte Klasse rausgekramt und dabei ist mir aufgefallen, das eine mögliche Deadlock Gefahr besteht. Allerdings bin ich mit der Lösung noch nicht 100% zufrieden

    Folgende Ausgangslage:

    - receiveData() wird für N Elemente aufgerufen, deren Daten in einem gemeinsamen Datenpool gespeichert werden. Sobald für das erste Element diese Funktion aufgerufen wird, soll die Aktualisierung der Daten aktivert werden und der aufrufende Prozess blockiert werden bis:

    - updateDataPool( vec ) den Pool aktualisiert hat. Diese Methode darf aber erst dann ausgeführt werden, wenn dies von receiveData() angefordert wurde. Das Update wird stets von einem anderen Thread durchgeführt.

    - prepareForReceive() ist eine Hilfsfunktion der Basisklasse, die immer for receiveData aufgerufen wird.

    Meine bisherige Lösung:

    struct DataPool{
       DataPool() 
        :   nofElements(10), counterPrepareForReceive(0), counterReceive(0)
          , performPoolUpdate(false), updatedPool 
       {
          //...
       }
       void prepareForReceive()
       {
          counterPrepareForReceive++;
          if( counterPrepareForReceive == nofElements )
          {
             boost::mutex::scoped_lock lock(mutex); 
             counterPrepareForReceive = 0;
             //udpdate ermoeglichen:
             this->performPoolUpdate  = true; 
             performPoolUpdateCond.notify_one();
          }
       }
       void receiveData()
       {
          if( counterReceive == 0 )
          {
             boost::mutex::scoped_lock lock(newPoolDataMutex); 
             //auf update warten
             while(!this->poolWasUpdated)
                waitForPoolUpdateCond.wait(lock);
          }
          counterReceive++;
          if( counterReceive == nofElements ) counterReceive = 0;
       }
       void updateDataPool(const Pool& pool)
       {
          boost::mutex::scoped_lock lock(mutex); 
          while(!this->performPoolUpdate)
             this->performPoolUpdateCond.wait(lock); 
    
          /* ... update pool ...*/
    
          //erfolgreiches update bekannt geben
          this->poolWasUpdated= true; 
          this->waitForPoolUpdateCond.notify_one(); 
       }
       int              nofElements;
       int              counterPrepareForReceive;
       int              counterReceive;
    
       boost::mutex     mutex;
       bool             performPoolUpdate;
       bool             poolWasUpdated;
       boost::condition performPoolUpdateCond;
       boost::condition waitForPoolUpdateCond};
    };
    //thread1
    int main()
    {
       for(int i=0; i<nofElements; i++) dataObj->prepareForReceive();
       for(int i=0; i<nofElements; i++) dataObj->receiveData();
    
       for(int i=0; i<nofElements; i++) dataObj->prepareForReceive();
       for(int i=0; i<nofElements; i++) dataObj->receiveData();
    
       //...
    }
    //thread2
    int main()
    {
       dataObj->updateDataPool();
       dataObj->updateDataPool();
       //...
    }
    

    An den Methoden und an der Aufrufalgorithmik kann ich nichts ändern, die sind von aussen fix vorgegeben. Es stet mir aber frei prepareForReceive() nicht zu verwenden und eine doNothing Methode draus zu machen.

    Frage:
    Kann ich hier die Snychroisierung evtl. optimieren? Irgendwie sieht das doppelt gemoppelt aus 😃


Anmelden zum Antworten