2016-10-25 10 views
0

標準のライブラリだけを使用してC++(11はOkです)で実装したいと思っているかなり基本的な問題に直面しています。C++(11)タイマー:アイドルまで蓄積する

与えられた回数だけ呼び出すことができる関数 "Message()"を想定します。一定時間呼び出されずにアクションをトリガーしたいとします。例:

Message(); 
Message(); 
Message(); 
Message(); 
sleep(10); <-- the idle time triggers an action 
Message(); 

これは意味があります。

私がこれまで実装した方法は、非同期whileループと、メッセージが入る度にパルスする条件変数の組み合わせを使用しています。CVがタイムアウトすると、私はアクションを実行します。擬似コードで

void Message(){ 
    unique_lock ul(M); 
    new_message = false; 
    CV.notify(); 
} 

... 

future = std::async([]{ 
    do { 
    unique_lock ul(M); 
    new_message = false; 
    got_message_within_time = CV.wait_for(ul, 20ms, new_message==true); 
    } while got_message_within_time; 
    // Got a timeout here... 
    time_to_take_action(); 
}); 

... 

Message() 
Message() 
Message() 
sleep(10) 

は、私は、これはそこに最もエレガントなソリューションです確信していない、誰もがより良い提案を持っていますか?すべて私が実装するすべての基本的な文がある中で:

「私はあなたを呼び出して停止したら、何かを」すべてのヘルプ/提案は

おかげで大歓迎です!

+1

メッセージで頻繁にタイマーをリセットするようなものがある場合は、スレッド化する必要はありません。そうでなければ、まともな解決策を書いたと思います。リソースがあまりフレンドリーではありませんが、 – David

+0

ポーリングが受け入れられるならば、より簡単なアプローチは、各メッセージで更新されるウォッチドッグスレッドと原子タイムスタンプです。ウォッチドッグは最後のタイムスタンプをチェックし、しきい値よりも大きければアクションを実行します。 – xvan

+0

David、Xvan、ポーリングによるウォッチドッグのアプローチは実際にはうまくいくかもしれませんが、メッセージのバーストが非常にまばらになる場所では継続的に実行する必要があります。私はそれについて考える必要があります。 いくつかのコンテキスト:私はRPiでホームオートメーションのものを実装しています:私が使用しているボタンは、押されている間、自分のアドレスを送信し続けます(私には分かりません...私は、それらを作る;-))。私はこれらをプレスのアドレス/期間に翻訳したいと思っています – Tvdp

答えて

0

私はあなたのやり方と似た方法を使いますが、監視スレッドを実行したままにしておきます。

#include <chrono> 
#include <iostream> 
#include <thread> 

using namespace std::chrono; 

time_point<steady_clock> lastMessage(steady_clock::now()); 
bool shutdown(false); 

void InactiveMessageLoop(){ 
    while(!shutdown){ 
     if((steady_clock::now() - lastMessage) > milliseconds(1000)){ 
      std::cout << "Are you still there?" << std::endl; 
     } 
     std::this_thread::sleep_for(milliseconds(1000)); 
    } 
    std::cout << "No hard feelings." << std::endl; 
} 

void Message(){ 
    lastMessage = steady_clock::now(); 
    // do stuff; 
} 

int main(){ 
    std::thread MessageThread(InactiveMessageLoop); 

    Message(); 
    Message(); 

    std::this_thread::sleep_for(milliseconds(5000)); 

    Message(); 
    Message(); 

    shutdown = true; 

    if(MessageThread.joinable()) MessageThread.join(); 

    return 0; 
} 

また、あなたが信号を送るに見ることができるが、それは単に、信号関数の内部でビジネスロジックを置くために、その考えられて悪い習慣から、メッセージのチェック機能を呼び出して、あなたのコードをインターレースするために、おそらく同じように効果的です。

編集:最後に結合を追加しました。

+0

Windowsでこのコードを使用するかどうか注意してください。子スレッドの前にメインスレッドが存在する場合、Visual Studioで生成されたコードの一部のバージョンでデッドロックが発生することがあります。 – Xiver

関連する問題