boost.asio源码阅读(2) - task_io_service

1.0 task_io_service

在boost.asio源码阅读(1)中,代码已经查看到task_io_service中。
具体的操作调用void task_io_service::init_task()
本文从init_task出发,查看到底basic_socket_acceptor的创建对task_io_service产生了什么影响.

1.1 init_task

直接上代码

void task_io_service::init_task()
{
  mutex::scoped_lock lock(mutex_);
  if (!shutdown_ && !task_)
  {
    1. task_ = &use_service<reactor>(this->get_io_service());
    2. op_queue_.push(&task_operation_);
    3. wake_one_thread_and_unlock(lock);
  }
}
  1. 创建task_,其实task_就是epoll_reactor.
  2. 将成员task_operation_放入队列
  3. 唤醒一个线程,并对当前操作解锁。
    这里能够明确io_service使用了同步队列op_queue(lock->入队->唤醒->unlock),在basic_socket_acceptor
    创建时,将task_operation_放入队列,在io_service->run()中,这个变量将会被操作.

1.2 task_io_service::run

直奔主题

std::size_t task_io_service::run(boost::system::error_code& ec)
{
  // ......
  thread_info this_thread;
  this_thread.private_outstanding_work = 0;
  // ......
  for (; do_run_one(lock, this_thread, ec); lock.lock())
  //......
}

thread_info 内部含有一个队列,也就是说在多线程调用io_service::run的时候
每一个线程将会具有自己的私有队列。

std::size_t task_io_service::do_run_one
{
  while (!stopped_)
  {
    if (!op_queue_.empty())
    {
      // Prepare to execute first handler from queue.
      operation* o = op_queue_.front();
      op_queue_.pop();
      bool more_handlers = (!op_queue_.empty());

      1. if (o == &task_operation_)
      {
        task_interrupted_ = more_handlers;

        if (more_handlers && !one_thread_)
          wakeup_event_.unlock_and_signal_one(lock);
        else
          lock.unlock();

        2. task_cleanup on_exit = { this, &lock, &this_thread };
        (void)on_exit;
        task_->run(!more_handlers, this_thread.private_op_queue);
      }
      else
      {
        std::size_t task_result = o->task_result_;

        if (more_handlers && !one_thread_)
          wake_one_thread_and_unlock(lock);
        else
          lock.unlock();

        // Ensure the count of outstanding work is decremented on block exit.
        4. work_cleanup on_exit = { this, &lock, &this_thread };
        (void)on_exit;

        // Complete the operation. May throw an exception. Deletes the object.
        o->complete(*this, ec, task_result);

        return 1;
      }
    }
    else
    {
      wakeup_event_.clear(lock);
      5. wakeup_event_.wait(lock);
    }
  }

  return 0;
}
  1. 如果当前操作的队列内容是task_operation_则最后会进入到task_->run也就是epoll_wait。
    同时,如果当前队列不为空且是多线程的时候,会继续唤醒线程来执行操作,避免epoll_wait阻赛带来的延迟(虽然可以打断)。
    到这里可以知道basic_socket_acceptor的创建使io_service->run的时候可以进入epoll_wait来处理相关的事件,
  2. 和line4相同,都是在定义一个变量后,执行对应的析构操作。同时将线程的私有队列的内容,添加到公有队列op_queue_中,最后将刚才出队的task_operation_重新加到队尾(task_cleanup),使io_service在处理完队列之前的事件后,再次进入到task->run中。
  3. line5表示在队列为空时,线程进入睡眠等待唤醒。

2. 小结

  1. 在本文中,可以知道basic_socket_acceptor的创建使io_service在循环事件时能够进入到epoll_wait。
    当然如果这时使用者将acceptor删除也不能改变io_service->run本身的逻辑,也就是说,如果acceptor不在需要,io_service要么停止或者重新开始,避免epoll_wait上面不必要的效率损失。
  2. task_io_service本身有一个公共队列,同时每一个执行线程有自己的私有队列,在每次处理事件之前,会将
    私有队列的内容先加入到公有队列中。在某种程度上,公有队列的内容要比私有队列的优先级高些。
  3. asio的所有事件,最后都会回到公有队列中等待被执行。

转载于:https://www.cnblogs.com/eskylin/p/6590832.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值