title: Implementing an event timer using boost::asio
body: <p>The sample code looks long, but actually it's not so complicated :-)</p>
  
  <p><strong>What I'm trying to do is, when a user calls EventTimer.Start(), it will execute the callback handler (which is passed into the ctor) every <code>interval</code> milliseconds for <code>repeatCount</code> times.</strong></p>
  
  <p>You just need to look at the function EventTimer::Stop()</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;string&gt;
  
  #include &lt;boost/asio.hpp&gt;
  #include &lt;boost/bind.hpp&gt;
  #include &lt;boost/thread.hpp&gt;
  #include &lt;boost/function.hpp&gt;
  #include &lt;boost/date_time/posix_time/posix_time.hpp&gt;
  
  #include &lt;ctime&gt;
  #include &lt;sys/timeb.h&gt;
  #include &lt;Windows.h&gt;
  
  std::string CurrentDateTimeTimestampMilliseconds() {
      double ms = 0.0;            // Milliseconds
  
      struct timeb curtime;
      ftime(&amp;curtime);
      ms = (double) (curtime.millitm);
  
      char timestamp[128];
  
      time_t now = time(NULL);
      struct tm *tp = localtime(&amp;now);
      sprintf(timestamp, "%04d%02d%02d-%02d%02d%02d.%03.0f",
              tp-&gt;tm_year + 1900, tp-&gt;tm_mon + 1, tp-&gt;tm_mday, tp-&gt;tm_hour, tp-&gt;tm_min, tp-&gt;tm_sec, ms);
  
      return std::string(timestamp);
  }
  
  class EventTimer
  {
  public:
      static const int kDefaultInterval     = 1000;
      static const int kMinInterval         = 1;
      static const int kDefaultRepeatCount  = 1;
      static const int kInfiniteRepeatCount = -1;
      static const int kDefaultOffset       = 10;
  
  public:
      typedef boost::function&lt;void()&gt; Handler;
  
      EventTimer(Handler handler = NULL)
          : interval(kDefaultInterval),
            repeatCount(kDefaultRepeatCount),
            handler(handler),
            timer(io),
            exeCount(-1)
      {
  
      }
  
      virtual ~EventTimer()
      {
  
      }
  
      void SetInterval(int value)
      {
  //        if (value &lt; 1)
  //            throw std::exception();
  
          interval = value;
      }
  
      void SetRepeatCount(int value)
      {
  //        if (value &lt; 1)
  //            throw std::exception();
  
          repeatCount = value;
      }
  
      bool Running() const
      {
          return exeCount &gt;= 0;
      }
  
      void Start()
      {
          io.reset(); // I don't know why I have to put io.reset here,
                      // since it's already been called in Stop()
          exeCount = 0;
  
          timer.expires_from_now(boost::posix_time::milliseconds(interval));
          timer.async_wait(boost::bind(&amp;EventTimer::EventHandler, this));
          io.run();
      }
  
      void Stop()
      {
          if (Running())
          {
              // How to reset everything when stop is called???
              //io.stop();
              timer.cancel();
              io.reset();
  
              exeCount = -1; // Reset
          }
      }
  
  private:
      virtual void EventHandler()
      {
          // Execute the requested operation
          //if (handler != NULL)
          //    handler();
          std::cout &lt;&lt; CurrentDateTimeTimestampMilliseconds() &lt;&lt; ": exeCount = " &lt;&lt; exeCount + 1 &lt;&lt; std::endl;
  
          // Check if one more time of handler execution is required
          if (repeatCount == kInfiniteRepeatCount || ++exeCount &lt; repeatCount)
          {
              timer.expires_at(timer.expires_at() + boost::posix_time::milliseconds(interval));
              timer.async_wait(boost::bind(&amp;EventTimer::EventHandler, this));
          }
          else
          {
              Stop();
              std::cout &lt;&lt; CurrentDateTimeTimestampMilliseconds() &lt;&lt; ": Stopped" &lt;&lt; std::endl;
          }
      }
  
  private:
      int                         interval;    // Milliseconds
      int                         repeatCount; // Number of times to trigger the EventHandler
      int                         exeCount;    // Number of executed times
      boost::asio::io_service     io;
      boost::asio::deadline_timer timer;
      Handler                     handler;
  };
  
  int main()
  {
      EventTimer etimer;
  
      etimer.SetInterval(1000);
      etimer.SetRepeatCount(1);
  
      std::cout &lt;&lt; CurrentDateTimeTimestampMilliseconds() &lt;&lt; ": Started" &lt;&lt; std::endl;
      etimer.Start();
      // boost::thread thrd1(boost::bind(&amp;EventTimer::Start, &amp;etimer));
  
      Sleep(3000); // Keep the main thread active
  
      etimer.SetInterval(2000);
      etimer.SetRepeatCount(1);
  
      std::cout &lt;&lt; CurrentDateTimeTimestampMilliseconds() &lt;&lt; ": Started again" &lt;&lt; std::endl;
      etimer.Start();
      // boost::thread thrd2(boost::bind(&amp;EventTimer::Start, &amp;etimer));
  
      Sleep(5000); // Keep the main thread active
  }
  
  /* Current Output:
  20110520-125506.781: Started
  20110520-125507.781: exeCount = 1
  20110520-125507.781: Stopped
  20110520-125510.781: Started again
   */
  
  /* Expected Output (timestamp might be slightly different with some offset)
  20110520-125506.781: Started
  20110520-125507.781: exeCount = 1
  20110520-125507.781: Stopped
  20110520-125510.781: Started again
  20110520-125512.781: exeCount = 1
  20110520-125512.781: Stopped
   */
  </code></pre>
  
  <p>I don't know why that my second time of calling to EventTimer::Start() does not work at all.  My questions are:</p>
  
  <ol>
  <li><p>What should I do in
  EventTimer::Stop() in order to reset
  everything so that next time of
  calling Start() will work?</p></li>
  <li><p>Is there anything else I have to modify?</p></li>
  <li><p>If I use another thread to start the EventTimer::Start() (see the commented code in the main function), when does the thread actually exit?</p></li>
  </ol>
  
  <p>Thanks.</p>
  
  <p>Peter</p>