jeudi 2 juillet 2015

cancel a deadline_timer, callback trigger

I was suprised not to find a clock component in boost::asio (our any widely used library) so it tried making a simple, minimalistic, implementation for testing some of my code.

Using boost::asio::deadline_timer I made the following class

class Clock
{
    public:
        using callback_t = std::function<void(int, Clock&)>;
        using duration_t = boost::posix_time::time_duration;

    public:
        Clock(boost::asio::io_service& io,
              callback_t               callback = nullptr,
              duration_t               duration = boost::posix_time::seconds(1),
              bool                     enable   = true)
            : m_timer(io)
            , m_duration(duration)
            , m_callback(callback)
            , m_enabled(false)
            , m_count(0ul)
        {
            if (enable) start();
        }

        void start()
        {
            if (!m_enabled)
            {
                m_enabled = true;
                m_timer.expires_from_now(m_duration);
                m_timer.async_wait(std::bind(&Clock::tick, this));
            }
        }

        void stop()
        {
            if (m_enabled)
            {
                m_enabled = false;
                size_t c_cnt = m_timer.cancel();
                #ifdef DEBUG
                printf("[DEBUG@%p] timer::stop : %lu ops cancelled\n", this, c_cnt);
                #endif
            }
        }

        void tick()
        {
            #ifdef DEBUG
            printf("[DEBUG@%p] timer::tick : %s\n", this, m_enabled?"enabled":"disabled");
            #endif
            m_timer.expires_at(m_timer.expires_at() + m_duration);
            m_timer.async_wait(std::bind(&Clock::tick, this));
            if (m_callback) m_callback(++m_count, *this);
        }

        void              reset_count()                            { m_count = 0ul;         }
        size_t            get_count()                        const { return m_count;        }
        void              set_duration(duration_t duration)        { m_duration = duration; }
        const duration_t& get_duration()                     const { return m_duration;     }
        void              set_callback(callback_t callback)        { m_callback = callback; }
        const callback_t& get_callback()                     const { return m_callback;     }

    private:
        boost::asio::deadline_timer m_timer;
        duration_t                  m_duration;
        callback_t                  m_callback;
        bool                        m_enabled;
        size_t                      m_count;
};

Yet it looks like the stop method doesn't work. If I ask a Clock c2 to stop another Clock c1

boost::asio::io_service ios;
Clock c1(ios, [&](int i, Clock& self){
        printf("[C1 - fast] tick %d\n", i);
    }, boost::posix_time::millisec(100)
);
Clock c2(ios, [&](int i, Clock& self){
        printf("[C2 - slow] tick %d\n", i);
        c1.stop();
    }, boost::posix_time::millisec(1000)
);
ios.run();

I see both clocks ticking and c1 doesn't stop after one second. Yet -DDebug shows me that [DEBUG@0x7ffe5e5e0060] timer::stop : 1 ops cancelled and the m_enable flag is correct.

It looks like calling m_timer.cancel() doesn't do what it's suppose to do. Did I got somethign wrong ? Why is my callbacks still being called ?

Aucun commentaire:

Enregistrer un commentaire