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的所有事件,最后都会回到公有队列中等待被执行。
posted @ 2017-03-20 18:06  eskylin的笔记  阅读(984)  评论(0编辑  收藏  举报