1.muduo库如何支持多线程
- muduo支持多线程的方式:一个程序有多个EventLoop,一个EventLoop属于一个线程,也就是所谓的one Loop per thread
- EventLoopThread(IO线程类)
- EventLoopThreadPool(IO线程池类)
IO线程池的功能是开启若干个IO线程,并让这些IO线程处于事件循环的状态
2.multiple reactors
-
每个Reactor都属于一个线程;
-
mainReactor关注的是acceptor,也就是监听socket所关注的事件;
-
subReactor关注的是已连接socket所关注的事件,每次新到一个连接,就选择一个subReactor来处理该连接(也就选择了该Reactor所对应的线程来处理连接);
-
若没有一个subReactor,那么mainReactor既要处理监听socket和已连接socket的事件;
-
eg:35\jmuduo\muduo\net\EventLoopThreadPool.h
35\jmuduo\muduo\net\EventLoopThreadPool.cc
35\jmuduo\muduo\net\CMakeLists.txt
35\jmuduo\muduo\net\TcpServer.cc -
eg测试:35\jmuduo\tests\Reactor_test09.cc
35\jmuduo\tests\CMakeLists.txt -
测试:
(1)EventLoop loop;中包含一个boost::scoped_ptr poller_;里面会创建一个epoll_creat(),也就是说3号fd被poll fd所占用,称之为pollfd;第3个fd没有关注其某些事件,就不会调用updateChannel,所以也没有打印出来;
(2)boost::scoped_ptr timerQueue_;是4号fd,会关注timerQueue_的可读事件,从而调用了updateChannel(),从而调用了epoll的updateChannel();
(3)int wakeupFd_; wakeupFd_应该等于5;
(4)接下来是 TcpServer server_;它包含了一个Acceptor,boost::scoped_ptr acceptor_; (5)acceptor_又包含了一个监听socket(Socket acceptSocket_;),是6号fd;
(6)第七个fd是int idleFd_;第7个fd没有关注其某些事件,就不会调用updateChannel,所以也没有打印出来;
客户端telnet连接2个过来,服务端的日志如下:
只是运行服务端
当一个telnet连接过来,监听socket产生了可读事件,6这个socket产生了可读事件,打印printActiveChannels,且创建了一个新的socket,fd号=8,需要关注其可读事件
telnet客户端发送数据,此时是socket=8产生了可读事件
-
eg测试:35\jmuduo\tests\Reactor_test10.cc
35\jmuduo\tests\CMakeLists.txt -
测试:多线程程序的fd的使用情况。telnet启动2个客户端。
6号socket就是监听socket
6号socket就是主线程的EventLoop对象的返回的活跃的Accept通道
接着创建一个新的连接出来,分配一个线程来处理。10是第一个IO线程的EventLoop对象的wakeupFd被唤醒了。
// 由于当前线程与ioLoop所属的线程不在同一个线程,把connectEstablished加入到ioLoop线程所属的EventLoop队列中
ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));
13号fd被唤醒,与上分析方法类似
客户端发送数据,那么可以看到对应的printActiveChannels的wakeupFd_处理可读事件。下面是2个telnet客户端,发送数据的情况