2017-04-26 3 views
0

C++/stdlibで定期的に発生するタイマー機能をインストールする簡単な方法はありますか?私はループを取り除きたい:reoccurringタイマー機能をインストールするには?

using namespace std::chrono; // literal suffixes 
auto tNext = steady_clock::now(); 
while (<condition>) { 
    std::this_thread::sleep_until(tNext); 
    tNext = tNext + 100ms; 
    ... 

その機能は、独自のスレッドで実行されます。私はあなたが欲しいものを推測している

+1

プログラムが他の処理をしている間に、タイマーを非同期で動作させたいのですか?次に、時間内のプロセスをスレッド内に置く必要があります。 –

+0

@JasonLangもちろん、独自のスレッド – towi

+0

'ping(100ms、callback)'の行に沿って何かをしたいのですか? –

答えて

0

この

int i = 10; 
auto pred = [i]() mutable {return i--;}; 
auto print = []{cout << "." << endl;}; 

timer t{500ms}; 
t.push({print, pred}); //asynchronously prints '.' 10 times within 5s 

//do anything else 

と仮定すると、パフォーマンスが重要ではなく、タイマーは、多くの場合、十分な機能を提供する必要があり、以下、更新されないです。

#include<functional> 
#include<vector> 
#include<thread> 
#include<utility> 
#include<chrono> 
#include<mutex> 
#include<atomic> 

class timer final 
{ 
public: 
    using microseconds = std::chrono::microseconds; 

    using predicate = std::function<bool()>; 
    using callback = std::function<void()>; 
    using job = std::pair<callback, predicate>; 

    explicit timer(microseconds t) : done{false}, period{t} 
    { 
     std::lock_guard<std::mutex> lck(mtx); 

     worker = std::thread([this]{ 
      auto t = std::chrono::steady_clock::now(); 
      while(!done.load()) 
      { 
       std::this_thread::sleep_until(t); 
       std::lock_guard<std::mutex> lck(mtx); 
       t += period; 
       for(auto it = jobs.begin(); it != jobs.end();) 
       { 
        if(it->second()) 
         it++->first(); 
        else 
         it = jobs.erase(it); 
       } 
      } 
     }); 
    } 

    ~timer() 
    { 
     done.store(true); 
     worker.join(); 
    } 

    void set_period(microseconds t) 
    { 
     std::lock_guard<std::mutex> lck(mtx); 
     period = t; 
    } 
    void push(const callback& c) 
    { 
     std::lock_guard<std::mutex> lck(mtx); 
     jobs.emplace_back(c, []{return true;}); 
    } 
    void push(const job& j) 
    { 
     std::lock_guard<std::mutex> lck(mtx); 
     jobs.push_back(j); 
    } 

private: 
    std::mutex mtx; 
    std::atomic_bool done; 
    std::thread worker; 

    std::vector<job> jobs; 
    microseconds period; 
}; 

timerコールは、以前は定期callback Sをプッシュし、predicatefalseに評価された場合、timerからcallbackを削除します。 timerオブジェクトは独自の有効期間を持ち、そのワーカースレッドは生きている間だけ存続します。

複数のjobを1つのtimerに含める理由は、1つのスレッドのみを使用して一緒に呼び出され、互いに同期するためです。

あなたはタイマー>万回秒を更新することを計画している場合を除き、mutex心配<は1msの期間を持っているか、非常に時間がかかるcallback Sを持っていません。

+0

はい、それは私が求めたものを超えて、実際には非常に便利な美しい解決策です。小さな質問です。なぜなら、私はアトミックにあまり精通していないからです。 'atomic_bool'の代わりに' atomic_flag'を使用できますか?すべてのシステムでロックフリー保証付きの唯一の原子が聞こえます。 – towi

+0

@towiあなたはそれを動作させることができますが、それは少しclunkyを取得します。しかし、2つのことに注意してください:最初に、ロックレスは基本的にここでは何の問題もありません。第二に、それが規格によって保証されていなくても、実際にはロックレスであることが最も確実です。 –

関連する問題