当我需要运行io_service和为什么

When I need to run io_service and why

本文关键字:service 为什么 io 运行      更新时间:2023-10-16

我有以下代码:

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time.hpp>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <map>
#include <utility>
namespace koicxx {
template <typename T>
class temp_storage : private boost::noncopyable
{
  typedef boost::shared_ptr<boost::asio::deadline_timer>                    shared_timer_t;
  typedef std::map<T, shared_timer_t>                                       timer_map_t;
  typedef std::pair<T, shared_timer_t>                                      timer_pair_t;
  typedef boost::function<void(const T&, const boost::system::error_code&)> callback_t;
public:
  temp_storage(boost::asio::io_service& io_service) :
    _io_service(io_service) {}
  bool add(const T& element, const boost::asio::deadline_timer::duration_type& timeout, callback_t callback = callback_t())
  {
    boost::lock_guard<boost::mutex> lock(_sync);
    const std::pair<timer_map_t::iterator, bool>& res =
      _internal_storage.insert(
        timer_pair_t(
          element
          , shared_timer_t(new boost::asio::deadline_timer(_io_service, timeout))
        ));
    if (!res.second)
    {
        return false;
    }
    const timer_map_t::iterator& itr = res.first;
    if (callback)
    {
      itr->second->async_wait(
        boost::bind(
          callback
          , itr->first
          , boost::asio::placeholders::error
        ));
    }
    itr->second->async_wait(
      boost::bind(
        &temp_storage::remove_callback
        , this
        , itr->first
        , boost::asio::placeholders::error
      ));
    return true;
  }
  bool remove(const T& element)
  {
    boost::lock_guard<boost::mutex> lock(_sync);
    const timer_map_t::iterator& itr = _internal_storage.find(element);
    if (itr == _internal_storage.end())
    {
        return false;
    }
    itr->second->cancel();
    _internal_storage.erase(itr);
    return true;
  }
  bool contains(const T& element)
  {
    boost::lock_guard<boost::mutex> lock(_sync);
    return _internal_storage.find(element) != _internal_storage.end();
  }
  void clear()
  {
    boost::lock_guard<boost::mutex> lock(_sync);
    for (timer_map_t::value_type& i : _internal_storage)
    {
        i.second->cancel();
    }
    _internal_storage.clear();
  }
private:
  void remove_callback(const T& element, const boost::system::error_code& e)
  {
    if (e == boost::asio::error::operation_aborted)
    {
        return;
    }
    remove(element);
  }
  boost::asio::io_service&  _io_service;
  timer_map_t               _internal_storage;
  boost::mutex              _sync;
};
} // namespace koicxx
int main()
{
  boost::asio::io_service io_service;
  koicxx::temp_storage<int> some_storage(io_service);
  some_storage.add(0, boost::posix_time::seconds(2));
  some_storage.add(1, boost::posix_time::seconds(3));
  some_storage.add(2, boost::posix_time::seconds(5));
  while (true)
  {
    if (some_storage.contains(0))
    {
      std::cout << 0 << ' ';
    }
    if (some_storage.contains(1))
    {
      std::cout << 1 << ' ';
    }
    if (some_storage.contains(2))
    {
      std::cout << 2 << ' ';
    }
    std::cout << 'n';
    boost::this_thread::sleep_for(boost::chrono::seconds(1));
  }
}

当我需要运行io_service,为什么?我可以让io_service成为类的成员吗?这个代码有什么问题吗?

你永远不会看到计时器过期。

当调用async_wait时,你告诉Asio的是:当计时器到期时,我希望你安排这个回调执行。注意,这里的"schedule"并不是指"立即执行",而是"将它插入到一个准备执行的队列中"。上述队列是io_service内部的一部分。在io_service上调用run会阻塞,直到所有挂起的工作调度完成并执行。

这里的问题是run等待两个已计划的回调(即。那些已经准备好执行的)和那些仍在等待调度的(即。那些你已经调用了async_wait,但计时器还没有过期的地方)。因此,从主线程调用run只会阻塞,直到所有三个计时器都过期,这可能不是您想要的。

你现在有两个选择:你可以打开第二个线程调用run。这是可行的,但最终会有两个线程基本上什么都不做(主线程,主要在循环中睡觉,而工作线程主要在run调用上睡觉)。

一种更轻量级的方法是从循环中调用poll。与run不同,poll只执行已经计划执行的回调,而不执行那些仍在等待的回调。如果没有这样的回调,poll立即返回,而不是阻塞:

template <typename T>
class temp_storage : private boost::noncopyable
{
public:
    void do_poll() {
         io_service_.poll();
    }
[...]
};
int main()
{
   [...]
   while (true)
   {
       [...]
       some_storage.do_poll();
       boost::this_thread::sleep_for(boost::chrono::seconds(1));
   }
}