views:

141

answers:

2

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?

+1  A: 

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).

Paul R
I don't believe thats a problem since my maximum frame rate will be 50 fps. Maybe I've got it wrong?But I take it from your answer that the accuracy difference is to small to make any difference.Though I would still like to know whats wrong in the second solution?
ronag
I'm not familiar with using boost for timing, but the bottom line is that for this application you don't need to worry about accuracy of better than ~ 10 ms, since you already have that much error, typically.
Paul R
+1  A: 

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();
}
Sam Miller
I don't see how that is any different from my second example?
ronag
my example uses `shared_from_this` and does not use threads, maybe those are subtle differences.
Sam Miller