muduo
为每个EventLoop
设计了runInLoop
和queueInLoop
函数用来将本该在其他线程执行的线程不安全函数放到它所属线程执行,从而达到线程安全。
muduo
采用采用one loop per thread
的设计思想,即每个线程运行一个循环,这里的循环也就是事件驱动循环EventLoop
。所以,EventLoop
对象的loop
函数,包括间接引发的Poller
的poll
函数,Channel的handleEvent函数,以及TcpConnection
的handle*
函数都是在一个线程内完成的。而在整个muduo
体系中,有着多个这样的EventLoop
,每个EventLoop
都执行着loop
,poll
,handleEvent
,handle*
这些函数。这种设计模型也被成为Reactor + 线程池
控制着这些EventLoop
的,换句话说,保存着事件驱动循环线程池的,就是TcpServer
类,服务器类。TcpServer类创建一个高并发的服务器,内部有一个线程池,线程池中有大量的线程,每个线程运行着一个事件驱动循环,one loop per thread
另外,TcpServer
本身也是一个线程(主线程),也运行着一个EventLoop
,这个事件驱动循环仅仅用来监控客户端的连接请求,即Acceptor
对象的Channel
的可读事件。通常如果用户添加定时器任务的话,也会由这个EventLoop
监听
但是TcpServer的这个EventLoop不在线程池中,这一点要区分开,线程池中的线程只用来运行负责监控TcpConnection的EventLoop的
TcpServer
的成员变量主要以EventLoop
,Acceptor
,TcpConnection
, EventLoopThreadLoop
为主,其它变量主要是各种用户提供的回调函数,大多都传给每一个TcpConnection
对象
typedef std::map<string, TcpConnectionPtr> ConnectionMap;
EventLoop* loop_; // the acceptor loop
//TcpServer所在的主线程下运行的事件驱动循环,负责监听Acceptor的Channel
const string ipPort_;//服务器负责监听的本地ip和端口
const string name_;//服务器名字,创建时传入
std::unique_ptr<Acceptor> acceptor_; // avoid revealing Acceptor
//Acceptor对象,负责监听客户端连接请求,运行在主线程的EventLoop中
std::shared_ptr<EventLoopThreadPool> threadPool_;
//事件驱动线程池,池中每个线程运行一个EventLoop
ConnectionCallback connectionCallback_;
//用户传入,有tcp连接到达或tcp连接关闭时调用,传给TcpConnection
MessageCallback messageCallback_;
//用户传入,对端发来消息时调用,传给TcpConnection
WriteCompleteCallback writeCompleteCallback_;
//成功写入内核tcp缓冲区后调用,传给TcpConnection
ThreadInitCallback threadInitCallback_;
//线程池初始化完成后调用,传给EventLoopThreadPool,再传给每个EventLoopThread
AtomicInt32 started_;
// always in loop thread
int nextConnId_;//TcpConnection特有id,每增加一个TcpConnection,nextConnId_加一
ConnectionMap connections_;//所有的TcpConnection对象,智能指针
};
- 事件驱动循环
EventLoop
如上所说,运行在主线程,只用来监听客户端连接请求(Acceptor)
,不负责监听TcpConnection
- 事件驱动循环线程池
EventLoopThreadPool
用于分发线程,当新建TcpConnection
时,从线程池中选出一个事件驱动循环线程负责这个TcpConnection
-
connections_
是std::map<string, shared_ptr<TcpConnection> >
类型,在新建TcpConnection
后会添加到这个map
中,可以保证每个TcpConnection
在添加后引用计数为1,保证生命期的正常管理。在tcp连接关闭后会从map中删除TcpConnection,使引用计数减1,为了防止引用计数为0导致没有从TcpConnection的函数中返回就已经将TcpConnection销毁,在removeConnectionInLoop中使用std::bind延长了TcpConnection的生命期,
⭐⭐⭐
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)