Accurate continuous timer callback
Ive got an application where I want to display a frame every x milliseconds.
Previously I did it like this:
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.
}
}
}
However I dont think solution has very good accuracy. I might be wrong?
I was hoping to used boost::asio::deadline_timer instead, but I'm unsure how to use it.
This is what ive tried, which doesn't seem to wait at all. It seems to just render the frames as fast as it can.
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();});
}
}
}
What am I doing wrong? And if I got this solution working would it be better than the first?
Here's a fairly trivial example using boost::asio::deadline_timer
, hopefully it helps
#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();
}
Remember that the accuracy with which a frame is displayed is limited by the refresh rate of your display (typically 17 ms for a 60 Hz display, or 13 ms for a 75 Hz display). If you're not syncing to the display refresh then you have an indeterminate latency of 0 - 17 ms to add to whatever timing method you use, hence accuracy doesn't really need be much better than 10 ms (even 1 ms is probably overkill).
精彩评论