一, 初始化一个tcp::socket socket_(io_service)时,最终会调用 io_service.init_task(),
1 void task_io_service::init_task() 2 { 3 mutex::scoped_lock lock(mutex_); 4 if (!shutdown_ && !task_) 5 { 6 task_ = &use_service<reactor>(this->get_io_service()); 7 op_queue_.push(&task_operation_); 8 wake_one_thread_and_unlock(lock); 9 } 10 }
从上面可以看出init_task时初始化一个task_,并把一个tak_operation_加入io_service公共队列op_queue中;( 1,task_就是一个epoll_reactor对象在其run函数中调用epoll_wait; 2,task_operation_是operation的一个派生类; )
然后唤醒一个空闲线程来执行op_queue中的任务;
二,假设用同一个io_service开启了4个线程,每个线程执行io_service::run()
1,io_service::run()在linux下最终会调用task_io_service::run(),进行调用task_io_service::do_run_one()函数
Thread_1在运行run()时发现io_service.op_queue不为空,取出一个op,发现此op就是之前投递的task_operation_则调用task_->run(),来调用epoll_wait();
此时线程的运行情况是这样的:
Thread_1——————————————epoll_wait…
Thread_2——————————————阻塞
Thread_3——————————————阻塞
Thread_4——————————————阻塞
注意:Thread_1的task_->run()执行完后,会把通过epoll_wait放入当前线程私有队列的任务,全部移到io_service.op_queue中,同时会把task_operation_放入到io_service.op_queue队列末尾;
2,假设经过很久以后epoll_wait监听到了很多任务,比如有5个IO任务,一个task_operation_,则线程的运行情况是这样的
Thread_1——————从op_queue中取出一个Op1,检查公共队列是否为空,不为空唤醒一个空闲线程,不是task, o->complete—————running......
Thread_2——————从op_queue中取出一个Op2,检查公共队列是否为空,不为空唤醒一个空闲线程,不是task, o->complete—————running......
Thread_3——————从op_queue中取出一个Op3,检查公共队列是否为空,不为空唤醒一个空闲线程,不是task, o->complete—————running......
Thread_4——————从op_queue中取出一个Op4,检查公共队列是否为空,不为空唤醒一个空闲线程,不是task, o->complete—————running......
......
Thread_1——————从op_queue中取出一个Op5,检查公共队列是否为空,不为空唤醒一个空闲线程,不是task, o->complete()—————running......
Thread_2——————从op_queue中取出一个Op6,检查公共队列是否为空,已经为空,是task,task_->run()—————epoll_wait......
Thread_3——————公共队列为空—————waiting......
Thread_4——————公共队列为空—————waiting......
三,上面就是io_service的简单运行过程
通过上面可以发现以下几点信息:
1,每一个io_service都有一个公共队列op_queue_,供多线程访问;
2,每一个线程都有一个私有队列private_op_queue_;
3,epoll_wait是在多线程间来回切换的,只有一个线程会执行epoll_wait;
4,每一个io_service对应一个epoll_wait;