Muduo学习笔记之EventLoop巧妙的线程切换

从上面两篇博文可知,每个线程有且只有一个EventLoop对象,其中IO线程是老大,线程池里面的线程只负责处理某一个客户端的请求。那么,如何从非IO线程切换到IO线程呢?EventLoop类里面新增了一个RuninLoop()函数。如果用户在当前IO线程调用这个函数,回调会同步进行,如果用户在其他线程调用这个函数,cb(用户回调函数)会被假如IO线程的队列,IO线程将被唤醒来调用这个cb。这里我感觉设计的特别巧妙,也是muduo作者的过人之处。

Muduo学习笔记之EventLoop巧妙的线程切换
有了这个函数,我们就可以轻易的在线程间调配任务,将非IO线程的函数移到IO线程,这样还可以在不用锁的情况下保证线程安全性。看看上述函数用到的queueInLoop函数
Muduo学习笔记之EventLoop巧妙的线程切换

首先将cb加入函数队列,然后判断条件满足后进行weakup(),weakup()是怎么实现的呢?我们已经知道,在EventLoop中会调用poll(2)函数阻塞等待监听套接字的活动事件。EventLoop里面新增了几个成员:
Muduo学习笔记之EventLoop巧妙的线程切换
添加了一个 wakeupFd_以及wakeupChannel_;我们只需要往wakeUpFd_里面写入一个字节,这样IO线程从IO mulitiplexing阻塞中调用被返回。而在EventLoop::loop()函数中添加了一行代码用于唤醒后执行其他线程的cb。
Muduo学习笔记之EventLoop巧妙的线程切换
Muduo学习笔记之EventLoop巧妙的线程切换
值得注意的是,functor这个vector不是在临界区依次调用Functor,而实把回调利厄表Swap()到局部变量中,一方面减少了临界区的长度,相当于直接清空原来的函数队列,这样不会影响到其他线程调用queueInLoop,另一方面也避免了死锁,因为Functor可能会再次调用queueInLoop()。这里设计的也非常巧妙,值得学习。