2012-03-28 5 views
0

boost::timed_waitを使用して、イベントを待つか、5秒後にタイムアウトします。私の問題は、私のtimed_waitが初めて通知を受け入れるということです。boost :: timed_waitからの通知条件変数は一度しか動作しません

より正確には:

私は少しステートマシンのいくつかの種類があります。 Commandだけを非同期的にディスパッチし、それが正常に実行されたかどうかをチェックするだけでは何も行いません。これは、私の状態マシンがm_Condition.timed_wait(lock,timeout)を呼び出すコマンドをディスパッチした後であることを意味します。 (m_Conditionは、タイプがboost::condition_variableのメンバ変数です)。

この非同期呼び出しが成功した場合は、m_Conditionを通知するコールバック関数を呼び出す必要があります。コマンドが失敗した場合、コールバック関数を呼び出さないので、timed_waitがタイムアウトするはずです。したがって、コールバック関数は、m_Condition.notify_all()を呼び出す以外に何も機能しません。

問題はこれが最初に動作することだけです。これは、最初にnotify_all()が呼び出された後、その条件変数で再び機能しないことを意味します。私は自分のコールバックをチェックして、それはいつもnotify_all()を呼び出しますが、timed_waitはただ時間切れです。

たぶん、いくつかのサンプルコードは、それが少し明確にする:

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(); 
} 

だから私は今、何ができるのでしょうか? condition_variableを複数回使用することはできませんか?それとも何とかリセットする必要がありますか?どんな提案も歓迎です!

+0

あなたのコードで何が起こっているのかわからないので、条件変数はシグナルだけではなく、共有条件の変更を通知するために使用する必要があります。この例を参照してください:http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html – stefaanv

+0

あなたのコードでは、状態はビジー状態のフラグなので、stateMachine "busy = true; while(busy &&!rc){rc = m_Condition.timed_wait(...);}" – stefaanv

+0

@stefaanvあなたの提案をありがとう。私はあなたが投稿した記事を読んで、大丈夫です、たぶん私は 'timed_wait'を通常の意図した目的ではなく使っていますが、それでもやるべきことです。実際にそこで使った実装は、私のものと全く同じです。 2番目のコメントに:どのようなビジーフラグを行う必要がありますか?私の問題は、私の 'timed_wait'は最初の呼び出しの後にタイムアウトと' false'の戻り値だけを返すということです。私は 'notify_all()'を呼び出すことができます。何も変更しません:/ – Toby

答えて

0

私にとっては最も明るい時間ではありません。私は実際問題を解決しました。上記の投稿されたコードはコンパイルされ、意図したとおりに動作します。実際の問題は、イベントまたはタイムアウトの処理中に嘘をつきました。ここで起こったことは絶対に無関係なので、ここで説明する必要はありません。だからこの質問は閉じられるでしょう。

UPDATE:もちろん

上記のコードは、発送方法の欠如ので、動作しません。テスト目的のために、私の主な機能にオブジェクトmyClass_Aを作成し、状態マシンを起動してから、私の主な機能からcallbackEventを呼び出してください。これは実際に動作します!

+0

さて、上記掲載のコードを実行ディスパッチもコールバックもないので、意図したとおりに動作することはできませんが、問題は解決されているので、これが最も重要です。 – stefaanv

+0

ちょっと更新しました – Toby

0

いいえ、条件変数をリセットする必要はありません。はい、複数回動作します。

私は、m_conditionで2回目を待つときに失敗するのではなく、デッドロックであると考えています。 stateMachine()でtimed_wait()を呼び出すと、mutexのロックが解除され、timed_wait()が戻るとロックされます。私はあなたがcallbackEvent()を呼び出している待機に続く欠落したコードでそれを推測しています。そのメソッドはmutexをロックしようとしますが、(a)呼び出し元(stateMachine())に既にロックされていて、(b)boost :: mutexがre-entrantではないからではありません。たとえば、代わりにrecursive_mutex。

+0

私もそうだと思っていましたが、コード(タイムアウトやイベントは省略しました)はそんなにあまりありません。したがって、これを実行すると、次のようになります。 1. 'timed_wait'が返ります(初回) 2.「イベント」コードが実行されます。 3.次のコマンドを 4. 'timed_wait'ミューテックス 5.コールバックは他に を実行することができますロックを解除ディスパッチされる - 私は、デバッガで確認 - 私のコードは実際には' notify_all'複数回 – Toby

関連する問題