<tfoot id='J1ZSM'></tfoot>
  • <small id='J1ZSM'></small><noframes id='J1ZSM'>

    1. <legend id='J1ZSM'><style id='J1ZSM'><dir id='J1ZSM'><q id='J1ZSM'></q></dir></style></legend>

      <i id='J1ZSM'><tr id='J1ZSM'><dt id='J1ZSM'><q id='J1ZSM'><span id='J1ZSM'><b id='J1ZSM'><form id='J1ZSM'><ins id='J1ZSM'></ins><ul id='J1ZSM'></ul><sub id='J1ZSM'></sub></form><legend id='J1ZSM'></legend><bdo id='J1ZSM'><pre id='J1ZSM'><center id='J1ZSM'></center></pre></bdo></b><th id='J1ZSM'></th></span></q></dt></tr></i><div id='J1ZSM'><tfoot id='J1ZSM'></tfoot><dl id='J1ZSM'><fieldset id='J1ZSM'></fieldset></dl></div>

        <bdo id='J1ZSM'></bdo><ul id='J1ZSM'></ul>

      1. 取消一个deadline_timer,无论如何都会触发回调

        cancel a deadline_timer, callback triggered anyway(取消一个deadline_timer,无论如何都会触发回调)

                  <tbody id='rTWp4'></tbody>
                <i id='rTWp4'><tr id='rTWp4'><dt id='rTWp4'><q id='rTWp4'><span id='rTWp4'><b id='rTWp4'><form id='rTWp4'><ins id='rTWp4'></ins><ul id='rTWp4'></ul><sub id='rTWp4'></sub></form><legend id='rTWp4'></legend><bdo id='rTWp4'><pre id='rTWp4'><center id='rTWp4'></center></pre></bdo></b><th id='rTWp4'></th></span></q></dt></tr></i><div id='rTWp4'><tfoot id='rTWp4'></tfoot><dl id='rTWp4'><fieldset id='rTWp4'></fieldset></dl></div>

                <small id='rTWp4'></small><noframes id='rTWp4'>

                  <bdo id='rTWp4'></bdo><ul id='rTWp4'></ul>
                • <legend id='rTWp4'><style id='rTWp4'><dir id='rTWp4'><q id='rTWp4'></q></dir></style></legend>

                • <tfoot id='rTWp4'></tfoot>
                  本文介绍了取消一个deadline_timer,无论如何都会触发回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                  问题描述

                  我很惊讶没有在 boost::asio(我们任何广泛使用的库)中找到时钟组件,所以它尝试制作一个简单、简约的实现来测试我的一些代码.

                  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.

                  使用 boost::asio::deadline_timer 我做了以下类

                  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(boost::bind(&Clock::tick, this, _1)); // std::bind _1 issue ?
                              }
                          }
                  
                          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
                  ", this, c_cnt);
                                  #endif
                              }
                          }
                  
                          void tick(const boost::system::error_code& ec)
                          {
                              if(!ec)
                              {
                                  m_timer.expires_at(m_timer.expires_at() + m_duration);
                                  m_timer.async_wait(boost::bind(&Clock::tick, this, _1)); // std::bind _1 issue ?
                                  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;
                  };
                  

                  但是看起来 stop 方法不起作用.如果我要求一个 Clock c2 停止另一个 Clock c1

                  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
                  ", i);
                      }, boost::posix_time::millisec(100)
                  );
                  Clock c2(ios, [&](int i, Clock& self){
                          printf("[C2 - slow] tick %d
                  ", i);
                          if (i%2==0) c1.start(); else c1.stop(); // Stop and start
                      }, boost::posix_time::millisec(1000)
                  );
                  ios.run();
                  

                  我看到两个时钟都按预期滴答作响,有时 c1 不会停止一秒钟,而它应该停止.

                  I see both clocks ticking as expected expect sometimes c1 doesn't stop for one second, while it should.

                  看起来由于某些同步问题,调用 m_timer.cancel() 并不总是有效.我做错了什么吗?

                  It looks like calling m_timer.cancel() doesn't always work because of some sync issue. Did I got somethign wrong ?

                  推荐答案

                  先把问题重现一下:

                  生活在 Coliru(代码如下)

                  如你所见,我运行它

                  ./a.out | grep -C5 false
                  

                  真的 c1_active 为假(并且完成处理程序不应运行)时,这会过滤从 C1 的完成处理程序打印的记录的输出

                  This filters the output for records that print from C1's completion handler when really c1_active is false (and the completion handler wasn't expected to run)

                  简而言之,问题是逻辑"竞争条件.

                  The problem, in a nutshell, is a "logical" race condition.

                  这有点令人费解,因为只有一个线程(在表面上可见).但其实并没有太复杂.

                  It's a bit of mind bender because there's only a single thread (visible on the surface). But it's actually not too complicated.

                  这是怎么回事:

                  • 当时钟 C1 到期时,它会将其完成处理程序发布到 io_service 的任务队列中.这意味着它可能不会立即运行.

                  • when Clock C1 expires, it will post its completion handler onto the io_service's task queue. Which implies that it might not run immediately.

                  想象一下 C2 也过期了,它的完成处理程序现在被调度并在 C1 刚刚推送的处理程序之前执行.想象一下,这次巧合的是,C2 决定在 C1 上调用 stop().

                  imagine that C2 expired too, and it's completion handler now gets scheduled and executes before the one that C1 just pushed. Imagine that by some high coincidence this time, C2 decides to call stop() on C1.

                  在 C2 的完成处理程序返回后,C1 的完成处理程序被调用.

                  After C2's completion handler returns, C1's completion handler gets invoked.

                  OOPS

                  它仍然有 ec 说没有错误"......因此 C1 的截止时间计时器被重新安排.糟糕.

                  It still has ec saying "no error"... Hence the deadline timer for C1 gets rescheduled. Oops.

                  有关 Asio(不会)为完成处理程序执行顺序做出的保证的更深入背景,请参阅

                  For a more in-depth background on the guarantees that Asio (doesn't) make(s) for the order in which completion handlers get executed, see

                  • 何时取消处理程序boost::asio 处理程序可以运行吗?

                  最简单的解决方案是意识到m_enabled 可能是false.让我们添加检查:

                  The simplest solution is to realize that m_enabled could be false. Let's just add the check:

                  void tick(const boost::system::error_code &ec) {
                      if (!ec && m_enabled) {
                          m_timer.expires_at(m_timer.expires_at() + m_duration);
                          m_timer.async_wait(boost::bind(&Clock::tick, this, _1));
                  
                          if (m_callback)
                              m_callback(++m_count, *this);
                      }
                  }
                  

                  在我的系统上它不再重现该问题:)

                  On my system it doesn't reproduce the problem any more :)

                  生活在 Coliru

                  #include <boost/asio.hpp>
                  #include <boost/bind.hpp>
                  #include <boost/date_time/posix_time/posix_time_io.hpp>
                  
                  static boost::posix_time::time_duration elapsed() {
                      using namespace boost::posix_time;
                      static ptime const t0 = microsec_clock::local_time();
                      return (microsec_clock::local_time() - t0);
                  }
                  
                  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(boost::bind(&Clock::tick, this, _1)); // std::bind _1 issue ?
                          }
                      }
                  
                      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
                  ", this, c_cnt);
                  #endif
                          }
                      }
                  
                      void tick(const boost::system::error_code &ec) {
                          if (ec != boost::asio::error::operation_aborted) {
                              m_timer.expires_at(m_timer.expires_at() + m_duration);
                              m_timer.async_wait(boost::bind(&Clock::tick, this, _1));
                              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;
                  };
                  
                  #include <iostream>
                  
                  int main() {
                      boost::asio::io_service ios;
                  
                      bool c1_active = true;
                  
                      Clock c1(ios, [&](int i, Clock& self)
                              { 
                                  std::cout << elapsed() << "	[C1 - fast] tick" << i << " (c1 active? " << std::boolalpha << c1_active << ")
                  ";
                              },
                              boost::posix_time::millisec(1)
                              );
                  
                  #if 1
                      Clock c2(ios, [&](int i, Clock& self)
                              {
                                  std::cout << elapsed() << "	[C2 - slow] tick" << i << "
                  ";
                                  c1_active = (i % 2 == 0);
                  
                                  if (c1_active)
                                      c1.start();
                                  else
                                      c1.stop();
                              },
                              boost::posix_time::millisec(10)
                          );
                  #endif
                  
                      ios.run();
                  }
                  

                  这篇关于取消一个deadline_timer,无论如何都会触发回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                  本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

                  相关文档推荐

                  Is Type(::x); valid?(是类型(::x);有效的?)
                  Difference between an inline function and static inline function(内联函数和静态内联函数的区别)
                  Compilation fails randomly: quot;cannot open program databasequot;(编译随机失败:“无法打开程序数据库)
                  Too many initializers error for a simple array in bcc32(bcc32 中的简单数组的初始值设定项过多错误)
                  No Member named stoi in namespace std(命名空间 std 中没有名为 stoi 的成员)
                  Error using a constexpr as a template parameter within the same class(在同一个类中使用 constexpr 作为模板参数时出错)

                • <legend id='jfXFQ'><style id='jfXFQ'><dir id='jfXFQ'><q id='jfXFQ'></q></dir></style></legend>
                    <bdo id='jfXFQ'></bdo><ul id='jfXFQ'></ul>
                    <i id='jfXFQ'><tr id='jfXFQ'><dt id='jfXFQ'><q id='jfXFQ'><span id='jfXFQ'><b id='jfXFQ'><form id='jfXFQ'><ins id='jfXFQ'></ins><ul id='jfXFQ'></ul><sub id='jfXFQ'></sub></form><legend id='jfXFQ'></legend><bdo id='jfXFQ'><pre id='jfXFQ'><center id='jfXFQ'></center></pre></bdo></b><th id='jfXFQ'></th></span></q></dt></tr></i><div id='jfXFQ'><tfoot id='jfXFQ'></tfoot><dl id='jfXFQ'><fieldset id='jfXFQ'></fieldset></dl></div>
                    <tfoot id='jfXFQ'></tfoot>
                      <tbody id='jfXFQ'></tbody>

                    <small id='jfXFQ'></small><noframes id='jfXFQ'>