CRTPでPollingスレッド

polling_base.hpp

#ifndef HWM_POLLING_BASE_HPP
#define HWM_POLLING_BASE_HPP

//! @file
//! do processing every specifiec time.

#include <boost/bind.hpp>
#include <boost/thread.hpp>

template<
    typename Derived,
    typename TimeDuration = boost::posix_time::time_duration
    >
class polling_base
{   
protected:
    //! ctor
    polling_base(   TimeDuration const  &waiting_time       = boost::posix_time::milliseconds(1000),
                    bool const          initial_suspended   = false)
        :   wait_       (waiting_time)
        ,   terminated_ (true)
        ,   suspended_  (initial_suspended)
    {
        initialize();
    }

    ~polling_base() { terminate(); }

public:
    TimeDuration const &    get_wait_time   ()  const { return wait_; }

    //! set waiting time.
    //! T must be assignable to TimeDuration
    template<typename T>
    void                    set_wait_time   (T const &wait) { wait_ = wait; }

    bool    is_suspended    () const { return suspended_; }
    
    void    suspend         ()
    {
        if(!is_suspended()) {
            boost::lock_guard<boost::mutex> lock(lock_);
            suspended_ = true;
        }
    }

    void    resume          ()
    {
        {
            boost::lock_guard<boost::mutex> lock(lock_);
            suspended_ = false;
        }
        cond_.notify_one();
    }

private:
    void    initialize      ()
    {
        if(is_terminated()) {
            terminated_ = false;
            thread_ = boost::thread(boost::bind(&polling_base::polling, this));
        }
    }

    void    terminate       ()
    {
        terminated_ = true;
        thread_.join();
    }

    bool    is_terminated   () const { return terminated_; }

    //! polling here
private:
    void    polling         ()
    {
        while(!is_terminated()) {
            boost::this_thread::sleep(wait_);

            boost::unique_lock<boost::mutex>    lock(lock_);
            while(is_suspended()) {
                cond_.wait(lock);
                if(is_terminated()) { goto BREAK_POLLING; }
            }

            //! Derived class processes.
            static_cast<Derived &>(*this).polling_process();
        }
BREAK_POLLING:
        (void *)0;
    }

private:
    boost::thread               thread_;
    boost::condition_variable   cond_;
    boost::mutex                lock_;
    TimeDuration                wait_;
    bool                        terminated_;
    bool                        suspended_;
};

#endif  //HWM_POLLING_BASE_HPP

test.cpp

#include <iostream>

#include "./polling.hpp"

class A
    :   public polling_base<A>
{
    typedef polling_base<A> base_type;
    
public:
    A()
        :   base_type(boost::posix_time::milliseconds(1000))
    {}
    
    //! これだけ定義
    void    polling_process()
    {
        std::cout << "Hello world." << std::endl;
    }
};

int main()
{
    A a;

    int dummy = 0;
    std::cin >> dummy;

    a.suspend();
    a.suspend();    //複数回呼んでも問題ない

    std::cout << "suspended" << std::endl;

    std::cin >> dummy;

    a.resume();
    a.resume();

    std::cout << "resumed" << std::endl;

    a.set_wait_time(a.get_wait_time() / 10);
    a.set_wait_time(a.get_wait_time() * 2);

    std::cin >> dummy;
}