2012-03-28 5 views
0

Ich möchte boost::timed_wait verwenden, um nach 5 Sekunden auf ein Ereignis oder Timeout zu warten. Mein Problem ist, dass meine timed_wait nur die Benachrichtigung zum ersten Mal akzeptiert.Benachrichtigen Bedingungsvariable von boost :: timed_wait funktioniert nur einmal

Um genauer zu sein:

ich eine Art von wenig Zustandsmaschine haben. Es führt nichts mehr aus, als einige Befehle asynchron auszuführen und dann zu überprüfen, ob es erfolgreich war. Dies bedeutet, dass nach dem Senden des Befehls meine Zustandsmaschine m_Condition.timed_wait(lock,timeout) aufruft. (m_Condition ist eine Elementvariable mit dem Typ boost::condition_variable).

Nun, wenn dieser asynchrone Aufruf erfolgreich war, sollte er eine Callback-Funktion aufrufen, die m_Condition benachrichtigt, damit ich weiß, dass alles in Ordnung ging. Wenn der Befehl fehlgeschlagen ist, ruft er die Callback-Funktion nicht auf und daher sollte meine timed_wait Timeout sein. Also die Callback-Funktion tut nichts mehr und nichts weniger als m_Condition.notify_all() aufrufen.

Das Problem ist, dass dies nur das erste Mal funktioniert. Dies bedeutet, dass nach dem ersten Aufruf von notify_all() diese Zustandsvariable nicht mehr funktioniert. Ich habe bei meinem Rückruf nachgesehen und es ruft immer wieder notify_all() an aber die timed_wait kommt gerade raus.

Vielleicht sind einige Beispiel-Code es ein wenig klarer zu machen:

myClass_A.hpp

class myClass_A 
{ 
public: 
    void runStateMachine();     // Starts the state machine 
    void callbackEvent();     // Gets called when Async Command was successful 
private: 
    void stateMachine();     // Contains the state machine 
    void dispatchAsyncCommand();   // Dispatches an Asynchronous command 
    boost::thread m_Thread;     // Thread for the state machine 
    boost::condition_variable m_Condition; // Condition variable for timed_wait 
    boost::mutex m_Mutex;     // Mutex 
}; 

myClass_A.cpp

void myClass_A::runStateMachine() 
{ 
    m_Thread = boost::thread(boost::bind(&myClass_A,this)); 
} 
void myClass_A::dispatchAsyncCommand() 
{ 
    /* Dispatch some command Async and then return */ 
    /* The dispatched Command will call callbackEvent() when done */ 
} 
void myClass_A::stateMachine() 
{ 
    boost::mutex::scoped_lock lock(m_Mutex); 
    while(true) 
    { 
     dispatchAsynCommand(); 
     if(!m_Condition.timed_wait(lock, boost::posix_time::milliseconds(5000))) 
     { 
      // Timeout 
     } 
     else 
     { 
      // Event 
     } 
    } 
} 
void myClass_A::callbackEvent() 
{ 
    boost::mutex::scoped_lock lock(m_Mutex); 
    m_Condition.notify_all(); 
} 

Also, was ich jetzt tun kann? Ist es nicht möglich, die condition_variable mehrmals zu verwenden? Oder muss ich es irgendwie zurücksetzen? Irgendwelche Vorschläge sind willkommen!

+0

Keine Antwort, weil ich nicht sicher bin, was in Ihrem Code vor sich geht, aber Zustandsvariablen sind nicht nur Signale, sie sollten verwendet werden, um eine Änderung in einem gemeinsamen Zustand zu signalisieren. Siehe dieses Beispiel: http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html – stefaanv

+0

In Ihrem Code könnte die Bedingung eine ausgelastete Flagge sein, also stateMachine könnte "busy = true; while (beschäftigt &&! rc) {rc = m_Condition.timed_wait (...);}" – stefaanv

+0

@stefaanv Vielen Dank für Ihre Vorschläge. Ich habe diesen Artikel gelesen, den du gepostet hast, und okay, vielleicht benutze ich den "timed_wait" nicht für den üblichen Zweck, aber trotzdem sollte es den Deal machen. Tatsächlich ist die Implementierung, die sie dort verwendeten, ziemlich die gleiche wie meine. Zu Ihrem zweiten Kommentar: Was sollte diese vielbefahrene Flagge tun? Ich meine mein Problem ist, dass mein 'timed_wait' nur mit einem Timeout und einem Rückgabewert von' false' nach dem ersten Anruf zurückkehrt. Ich kann 'notify_all()' alles, was ich will .. nichts ändern:/ – Toby

Antwort

0

Okay, nicht die hellste Stunde für mich Ich löste das Problem tatsächlich. Der oben angegebene Code kompiliert und funktioniert wie vorgesehen. Das eigentliche Problem lag im Umgang mit Event oder Timeout. Da das Zeug, das dort passiert ist, absolut nichts mit der timed_wait zu tun hat, denke ich, ich brauche es hier nicht zu erklären. So kann diese Frage geschlossen werden.

UPDATE:

Natürlich ist der obige Code wird, da der Mangel einer Dispatch Methode nicht. Nur um es mir zu sagen, ich werde es hier erwähnen: Zu Testzwecken erstelle ich einfach ein Objekt von myClass_A in meiner Hauptfunktion, starte den Zustandsautomaten und rufe dann die callbackEvent aus meiner Hauptfunktion heraus. Das funktioniert tatsächlich!

+0

Nun, die oben gepostet Code kann nicht wie vorgesehen funktionieren, weil es keine Versand und keinen Rückruf gibt, aber Ihr Problem ist gelöst, so dass das wichtigste ist. – stefaanv

+0

Okay, machte ein kleines Update – Toby

0

Nein, Sie müssen die Bedingungsvariable nicht zurücksetzen, und ja, es funktioniert mehrmals.

Ich glaube, was Sie sehen, ist ein Deadlock, anstatt Fehler beim zweiten Mal auf m_condition. Wenn Sie in stateMachine() timed_wait() aufrufen, wird Ihr Mutex entsperrt und erneut gesperrt, wenn timed_wait() zurückkehrt. Ich vermute, dass in dem fehlenden Code, der auf die Wartezeit folgt, CallbackEvent() aufgerufen wird. Diese Methode versucht, den Mutex zu sperren, aber es kann nicht, weil (a) sie bereits im Aufrufer gesperrt ist (stateMachine()) und (b) boost :: mutex nicht einspringt. Sie könnten versuchen, z.B. rekursiv_mutex stattdessen.

+0

dachte ich auch, aber der Code (den ich ausgelassen habe -> Timeout oder Event) ist nicht sehr viel. Also wenn ich das durchspiele würde es so gehen: 1. 'timed_wait' kehrt zurück (erstes mal) 2." Event "Code wird ausgeführt. 3. Als nächstes Kommando wird ausgelöst 4. 'timed_wait' der Mutex 5. Rückruf entriegelt Neben ausgeführt werden kann - ich mit dem Debugger kontrolliert - mein Code tatsächlich die' notify_all' mehrere Male ausführt – Toby

Verwandte Themen