2017-04-26 38 views
0

有沒有一種簡單的方法來安裝定期發生的定時器功能與C++/stdlib?我想擺脫循環:如何安裝重複定時器功能?

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,回調)'的行嗎? –

回答

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小號週期性,當predicate計算結果爲false,刪除從timercallback。對象具有其自己的生命週期,並且其工作線程只會活着。

原因是你想在一個timer中有多個job s,這樣它們將被一起調用,只使用一個線程並相互同步。

不要擔心mutex,除非您打算更新計時器>每秒10,000次,週期爲< 1ms或耗時非常耗時callback s。

+0

是的,這是一個很好的解決方案,超出了我的要求,在實踐中非常有用。小問題,因爲我不熟悉原子。你可以使用'atomic_flag'而不是'atomic_bool'嗎?我聽說它是​​所有系統上唯一的無鎖保證原子。 – towi

+0

@towi你可以使它工作,但它確實有點笨重。請注意兩點:首先,無鎖基本上根本就不重要。其次,即使標準沒有保證,但在實踐中肯定是無法實現的。 –