2010-07-25 74 views
1

我有一個應用程序,我希望每x毫秒顯示一個幀。準確的連續計時器回調

以前我做的是這樣的:

class SomeClass 
{ 
    boost::thread thread_; 
    boost::timer timer_; 
public: 
    SomeClass() : thread_([=]{Display();}) 
    { 
    } 

    void Display 
    {  
     double wait = 1.0/fps*1000.0;  
     while(isRunning_) 
     { 
      double elapsed = timer.elapsed()*1000.0; 
      if(elapsed < wait) 
        boost::this_thread::sleep(boost::posix_time::milliseconds(static_cast<unsigned int>(wait - elapsed))); 
      timer.restart(); 

      // ... Get Frame. This can block while no frames are being rendered. 

      // ... Display Frame. 
     } 
    } 
} 

不過,我不認爲解決方案有很好的精度。我可能錯了?

我希望能用boost :: asio :: deadline_timer代替,但我不確定如何使用它。

這是我試過的,這似乎沒有等待。它似乎只是儘可能快地渲染幀。

class SomeClass 
    { 
     boost::thread thread_; 
     boost::asio::io_service io_; 
     boost::asio::deadline_timer timer_; 

    public: 
     SomeClass() : timer_(io_, 1.0/fps*1000.0) 
     { 
      timer_.async_wait([=]{Display();}); 
      thread_ = boost::thread([=]{io_.run();}) 
     } 

     void Display 
     {  
       double wait = 1.0/fps*1000.0;  
       while(isRunning_) 
       { 
        timer_.expires_from_now(boost::posix_time::milliseconds(wait_)); // Could this overflow? 

        // ... Get Frame. This can block while no frames are being rendered. 

        // ... Display Frame. 

        timer_.async_wait([=]{Display();}); 
       } 
     } 
    } 

我在做什麼錯?如果我得到這個解決方案的工作會比第一個更好嗎?

+0

我不熟悉這個語法'timer_.async_wait([=] {顯示();});'它有什麼作用? – 2010-07-26 14:40:23

+0

如果你的意思是[=] {Display();}),那麼它只是一個C++ 11x lambda表達式。它是寫函數對象的簡寫。 – ronag 2010-08-06 18:14:34

回答

1

請記住,幀的顯示精度受顯示器的刷新率限制(典型值爲60 Hz顯示器爲17 ms,75 Hz顯示器爲13 ms)。如果你沒有同步到顯示刷新,那麼你有一個不確定的延遲0-17毫秒,以添加到你使用的任何計時方法,因此精度並不需要比10毫秒好得多(甚至1毫秒可能是矯枉過正)。

+0

我不相信這是一個問題,因爲我的最大幀率將是50幀/秒。也許我錯了? 但我從你的答案中看出,準確度差異很小,從而有所作爲。 儘管我仍然想知道第二種解決方案中最新的錯誤是什麼? – ronag 2010-07-25 12:26:43

+0

我對使用boost進行計時並不熟悉,但底線是,對於此應用程序,您不需要擔心精度優於〜10 ms,因爲通常您已經有了那麼多的錯誤。 – 2010-07-25 13:29:44

3

下面是使用boost::asio::deadline_timer一個相當簡單的例子,希望這有助於

#include <boost/asio.hpp> 
#include <boost/bind.hpp> 
#include <boost/enable_shared_from_this.hpp> 

#include <iostream> 

class Timer : public boost::enable_shared_from_this<Timer> 
{ 
public: 
    Timer(
      boost::asio::io_service& io_service 
     ) : 
     _io_service(io_service), 
     _timer(io_service) 
    { 

    } 

    void start() { 
     _timer.expires_from_now(
       boost::posix_time::seconds(0) 
       ); 
     _timer.async_wait(
       boost::bind(
        &Timer::handler, 
        shared_from_this(), 
        boost::asio::placeholders::error 
        ) 
       ); 
    } 

private: 
    void handler(
      const boost::system::error_code& error 
      ) 
    { 
     if (error) { 
      std::cerr << error.message() << std::endl; 
      return; 
     } 

     std::cout << "handler" << std::endl; 
     _timer.expires_from_now(
       boost::posix_time::seconds(1) 
       ); 
     _timer.async_wait(
       boost::bind(
        &Timer::handler, 
        shared_from_this(), 
        boost::asio::placeholders::error 
        ) 
       ); 
    } 

private: 
    boost::asio::io_service& _io_service; 
    boost::asio::deadline_timer _timer; 
}; 

int 
main() 
{ 
    boost::asio::io_service io_service; 
    boost::shared_ptr<Timer> timer(
      new Timer(io_service) 
      ); 
    timer->start(); 
    io_service.run(); 
} 
+0

我不明白這和我的第二個例子有什麼不同? – ronag 2010-07-27 22:11:22

+1

我的示例使用'shared_from_this'並且不使用線程,也許這些細微差別。 – 2010-07-30 13:07:45

+0

利用shared_from_this和定時器的週期性特性的組合,這並不意味着即使沒有外部共享指針指向Timer對象也永遠不會銷燬,因爲總會有共享回調中的指針? – oracal 2014-01-15 15:02:15