目前为止,涉及到的绝大多数操作都没有提及线程,EventLoop,Poller,Channel,Acceptor,TcpConnection,这些对象的执行都是在单独线程完成,并没有设计多线程的创建销毁等。除了runInLoop函数仅仅提及了线程安全性,发现原来其实是有多个线程在同时运行的,也发现某个对象可能会暴露给其他线程,这样不安全,为了解决不安全隐患,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类。顾名思义,服务器类,用来创建一个高并发的服务器,内部便有一个线程池,线程池中有大量的线程,每个线程运行着一个事件驱动循环,即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;
/* TcpServer所在的主线程下运行的事件驱动循环,负责监听Acceptor的Channel */
EventLoop* loop_; // the acceptor loop
/* 服务器负责监听的本地ip和端口 */
const string ipPort_;
/* 服务器名字,创建时传入 */
const string name_;
/* Acceptor对象,负责监听客户端连接请求,运行在主线程的EventLoop中 */
std::unique_ptr<Acceptor> acceptor_; // avoid revealing Acceptor
/* 事件驱动线程池,池中每个线程运行一个EventLoop */
std::shared_ptr<EventLoopThreadPool> threadPool_;
/* 用户传入,有tcp连接到达或tcp连接关闭时调用,传给TcpConnection */
ConnectionCallback connectionCallback_;
/* 用户传入,对端发来消息时调用,传给TcpConnection */
MessageCallback messageCallback_;
/* 成功写入内核tcp缓冲区后调用,传给TcpConnection */
WriteCompleteCallback writeCompleteCallback_;
/* 线程池初始化完成后调用,传给EventLoopThreadPool,再传给每个EventLoopThread */
ThreadInitCallback threadInitCallback_;
AtomicInt32 started_;
// always in loop thread
/* TcpConnection特有id,每增加一个TcpConne

本文详细介绍了muduo网络库中的TcpServer类,它是创建高并发服务器的核心,内部包含线程池和事件驱动循环。TcpServer使用一个事件驱动循环监听客户端连接请求,而线程池中的事件驱动循环负责处理 TcpConnection。Acceptor用于监听客户端请求,TcpConnection则处理数据通信。构造函数设置回调函数,当有新连接时创建TcpConnection。start()函数启动线程池,而loop()开始事件驱动循环。文章还提到了TcpServer的各种成员变量及其作用,以及如何在用户程序中使用TcpServer。
最低0.47元/天 解锁文章
532

被折叠的 条评论
为什么被折叠?



