EventLoopThread创建了一个线程在线程函数中创建了一个EvenLoop对象并调用EventLoop::loop
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
class EventLoopThread : boost::noncopyable
{ public: typedef boost::function< void(EventLoop *)> ThreadInitCallback; EventLoopThread( const ThreadInitCallback &cb = ThreadInitCallback()); ~EventLoopThread(); EventLoop *startLoop() // 启动线程,该线程就成为了IO线程 { thread_.start(); // 执行threadFunc(); 构造函数初始化列表中thread_(boost::bind(&EventLoopThread::threadFunc, this)) .... }; private: void threadFunc(); // 线程函数 EventLoop *loop_; // loop_指针指向一个EventLoop对象 bool exiting_; Thread thread_; MutexLock mutex_; Condition cond_; ThreadInitCallback callback_; // 回调函数在EventLoop::loop事件循环之前被调用 }; EventLoopThread::~EventLoopThread() { exiting_ = true; loop_->quit(); // 退出IO线程,让IO线程的loop循环退出,从而退出了IO线程 thread_.join(); }
C++ Code
{ EventLoop loop; if (callback_) { callback_(&loop); } { MutexLockGuard lock(mutex_); // 一般情况是EventLoopThread对象先析构,析构函数调用loop_->quit() 使得loop.loop() 退出循环 // 这样threadFunc 退出,loop栈上对象析构,loop_ 指针失效,但此时已经不会再通过loop_ 访问loop, // 故不会有问题。 loop_ = &loop; cond_.notify(); } loop.loop(); //assert(exiting_); } |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include #include #include using namespace muduo; using namespace muduo::net; void runInThread() { printf( "runInThread(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); } int main() { printf( "main(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); EventLoopThread loopThread; EventLoop *loop = loopThread.startLoop(); // 异步调用runInThread,即将runInThread添加到loop对象所在IO线程,让该IO线程执行 loop->runInLoop(runInThread); sleep( 1); // runAfter内部也调用了runInLoop,所以这里也是异步调用,让该IO线程添加一个2s定时器 loop->runAfter( 2, runInThread); sleep( 3); //~EventLoopThread()会调用loop_->quit(); printf( "exit main().\n"); } |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
class EventLoopThreadPool : boost::noncopyable
{ public: typedef boost::function< void(EventLoop *)> ThreadInitCallback; EventLoopThreadPool(EventLoop *baseLoop); ~EventLoopThreadPool(); void setThreadNum( int numThreads) { numThreads_ = numThreads; } void start( const ThreadInitCallback &cb = ThreadInitCallback()); // 如果loops_为空,则loop指向baseLoop_ // 如果不为空,按照round-robin(RR,轮叫)的调度方式选择一个EventLoop EventLoop *getNextLoop(); private: EventLoop *baseLoop_; // 与Acceptor所属EventLoop相同 bool started_; int numThreads_; // 线程数,除去mainReactor int next_; // 新连接到来,所选择的EventLoop对象下标 boost::ptr_vector std::vector }; void EventLoopThreadPool::start( const ThreadInitCallback &cb) { assert(!started_); baseLoop_->assertInLoopThread(); started_ = true; for ( int i = 0; i < numThreads_; ++i) { EventLoopThread *t = new EventLoopThread(cb); threads_.push_back(t); loops_.push_back(t->startLoop()); // 启动EventLoopThread线程,在进入事件循环之前,会调用cb } if (numThreads_ == 0 && cb) { // 只有一个EventLoop,在这个EventLoop进入事件循环之前,调用cb cb(baseLoop_); } } |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void TcpServer::newConnection(
int sockfd,
const InetAddress &peerAddr)
{ loop_->assertInLoopThread(); // 按照轮叫的方式选择一个EventLoop EventLoop *ioLoop = threadPool_->getNextLoop(); InetAddress localAddr(sockets::getLocalAddr(sockfd)); TcpConnectionPtr conn( new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr)); connections_[connName] = conn; ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn)); } |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
#include #include #include #include #include using namespace muduo; using namespace muduo::net; class TestServer { public: TestServer(EventLoop *loop, const InetAddress &listenAddr, int numThreads) : loop_(loop), server_(loop, listenAddr, "TestServer"), numThreads_(numThreads) { server_.setConnectionCallback( boost::bind(&TestServer::onConnection, this, _1)); server_.setMessageCallback( boost::bind(&TestServer::onMessage, this, _1, _2, _3)); server_.setThreadNum(numThreads); } void start() { server_.start(); } private: void onConnection( const TcpConnectionPtr &conn) { if (conn->connected()) { printf( "onConnection(): new connection [%s] from %s\n", conn->name().c_str(), conn->peerAddress().toIpPort().c_str()); } else { printf( "onConnection(): connection [%s] is down\n", conn->name().c_str()); } } void onMessage( const TcpConnectionPtr &conn, const char *data, ssize_t len) { printf( "onMessage(): received %zd bytes from connection [%s]\n", len, conn->name().c_str()); } EventLoop *loop_; TcpServer server_; int numThreads_; }; int main() { printf( "main(): pid = %d\n", getpid()); InetAddress listenAddr( 8888); EventLoop loop; TestServer server(&loop, listenAddr, 4); server.start(); loop.loop(); } |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 该函数多次调用是无害的 // 该函数可以跨线程调用 void TcpServer::start() { if (!started_) { started_ = true; threadPool_->start(threadInitCallback_); } if (!acceptor_->listenning()) { // get_pointer返回原生指针 loop_->runInLoop( boost::bind(&Acceptor::listen, get_pointer(acceptor_))); } } |