libmoost
/home/mhx/git/github/libmoost/include/moost/utils/fixed_interval_timer.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00035 #ifndef MOOST_FIXED_INTERVAL_TIMER_TIMER_HPP__
00036 #define MOOST_FIXED_INTERVAL_TIMER_TIMER_HPP__
00037 
00038 #include <csignal>
00039 #include <utility>
00040 #include <boost/function.hpp>
00041 #include <boost/thread.hpp>
00042 #include <boost/bind.hpp>
00043 #include <boost/shared_ptr.hpp>
00044 #include <boost/date_time/posix_time/posix_time.hpp>
00045 #include <boost/asio.hpp>
00046 #include <boost/ref.hpp>
00047 
00048 namespace moost { namespace utils {
00049 
00082    class fixed_interval_timer
00083    {
00084       private:
00085          typedef boost::promise<int> promise_t;
00086          typedef boost::shared_ptr<promise_t> promise_ptr;
00087          typedef std::sig_atomic_t volatile sig_atomic_t;
00088          typedef boost::shared_ptr<sig_atomic_t> signal_ptr;
00089 
00090       public:
00091          typedef boost::function0<void> callback_t;
00092          typedef std::pair<boost::posix_time::ptime, callback_t> process_arg;
00093 
00100          fixed_interval_timer(boost::posix_time::time_duration const & interval)
00101             : interval_(interval)
00102             , thread_(boost::bind(&boost::asio::io_service::run, &io_service_))
00103             , pwork_(new boost::asio::io_service::work(io_service_))
00104          {
00105          }
00106 
00110          ~fixed_interval_timer()
00111          {
00112             try
00113             {
00114                // right, down tools chaps
00115                pwork_.reset();
00116                thread_.join();
00117             }
00118             catch(...)
00119             {
00120                // oh, crap :(
00121             }
00122          }
00123 
00129          void notify(callback_t const & cb)
00130          {
00131             // notify me when this time has passed
00132             boost::posix_time::ptime pt =
00133                boost::posix_time::microsec_clock::universal_time() + interval_;
00134 
00135             // queue the notification request
00136             io_service_.post(boost::bind(
00137                &fixed_interval_timer::process, this,
00138                std::make_pair(pt, cb)));
00139          }
00140 
00144          typedef boost::unique_future<int> future_t;
00145 
00151          void notify(future_t & f_sig)
00152          {
00153             // signal me when this time has passed
00154             boost::posix_time::ptime pt =
00155                boost::posix_time::microsec_clock::universal_time() + interval_;
00156 
00157             // I promise to notify you in the future
00158             promise_ptr p_sig(new promise_t);
00159             f_sig = p_sig->get_future();
00160 
00161             // queue the notification request
00162             io_service_.post(boost::bind(
00163                &fixed_interval_timer::process, this,
00164                std::make_pair(pt, boost::bind(
00165                   &fixed_interval_timer::fulfil_promise, this, p_sig))
00166                ));
00167          }
00168 
00169 
00173          class signal_t
00174          {
00175             friend class fixed_interval_timer;
00176 
00177             public:
00178                signal_t()
00179                   : psig_(new sig_atomic_t(0)) {}
00180 
00181                bool is_ready() const
00182                {
00183                   return *psig_ == 1;
00184                }
00185 
00186             private:
00187                signal_ptr psig_;
00188          };
00189 
00195          void notify(signal_t & sig)
00196          {
00197             // signal me when this time has passed
00198             boost::posix_time::ptime pt =
00199                boost::posix_time::microsec_clock::universal_time() + interval_;
00200 
00201             // queue the signal request
00202             io_service_.post(boost::bind(
00203                &fixed_interval_timer::process, this,
00204                std::make_pair(pt, boost::bind(
00205                   &fixed_interval_timer::set_signal, this, sig.psig_))
00206                ));
00207          }
00208 
00209 
00210       private:
00211          // process the current queue item
00212          void process(process_arg const & arg) const
00213          {
00214             // sleep until it's time to call the callback
00215             boost::thread::sleep(arg.first);
00216 
00217             // call the callback
00218             arg.second();
00219          }
00220 
00221          // make good on our promise
00222          void fulfil_promise(promise_ptr p_sig) const
00223          {
00224             // a promise should never be broken!
00225             p_sig->set_value(1);
00226          }
00227 
00228          // signal that sucker
00229          void set_signal(signal_ptr psig) const
00230          {
00231             *psig = 1;
00232          }
00233 
00234       private:
00235          boost::posix_time::time_duration interval_;
00236          boost::asio::io_service io_service_;
00237          boost::thread thread_;
00238          boost::shared_ptr<boost::asio::io_service::work> pwork_;
00239    };
00240 
00241 }}
00242 
00243 #endif