muodu 开源阅读(一)

服务器的启动

创建一个TcpServer(包含EevntLoop,acceptor,EventThreadPool),调用setThreadNum设立线程的数目,然后调用Start()启动server。在start()中,线程池的创建由函数threadPool_->start(threadInitCallback_)完成;启动监听由loop_->runInLoop(boost::bind(&Acceptor::listen, get_pointer(acceptor_)))完成

线程池的创建

threadPool_->start(threadInitCallback_)的实现如下:


void EventLoopThreadPool::start(const ThreadInitCallback& cb)
{
  assert(!started_);
  baseLoop_->assertInLoopThread();


  started_ = true;


  for (int i = 0; i < numThreads_; ++i)
  {
    EventLoopThread* t = new EventLoopThread(cb);//new 一个 thread
    threads_.push_back(t);
    loops_.push_back(t->startLoop());
  }
  if (numThreads_ == 0 && cb)
  {
    cb(baseLoop_);
  }
}


EventLoopThread中包含一个Thread变量,其构造函数如下:

EventLoopThread::EventLoopThread(const ThreadInitCallback& cb)
  : loop_(NULL),
    exiting_(false),
    thread_(boost::bind(&EventLoopThread::threadFunc, this), "EventLoopThread"), // FIXME: number it
    mutex_(),
    cond_(mutex_),
    callback_(cb)
{


t->startLoop() 里面调用的几个关键函数的嵌套:Thread_.start()->EventLoopThread::threadFunc()。

其中threadFunc()通过Thread的构造函数bind住。然后 EventLoopThread通过如下两个函数的配合获取loop变量并启动loop()循环:


EventLoop* EventLoopThread::startLoop()
{
  assert(!thread_.started());
  thread_.start();//真正启动pthread_create(),进入startThread->runInThread->func
  {
    MutexLockGuard lock(mutex_);
    while (loop_ == NULL)
    {
      cond_.wait();
    }
  }
}


void EventLoopThread::threadFunc()
{
  EventLoop loop;


  if (callback_)
  {
    callback_(&loop);
  }
  {
    MutexLockGuard lock(mutex_);//unlock() is in deconstruct func
    loop_ = &loop;
    cond_.notify();
  }


  loop.loop();
  //assert(exiting_);
  loop_ = NULL;
}


 
  

可见loop只是一个栈变量。

启动监听

 loop_->runInLoop()主要启动监听,这时需要类Acceptor型的变量:

void Acceptor::listen()
{
  loop_->assertInLoopThread();//此段程序仍然在主线程中跑
  listenning_ = true;
  acceptSocket_.listen();
  acceptChannel_.enableReading();
}


因为acceptor完成的是监控连接的功能,其必然包含两个变量Channel和Socket.
acceptChannel主要是用来监听的channel,其handevent()最终会执行 acceptChannel_.setReadCallback(boost::bind(&Acceptor::handleRead, this));

Acceptor::handleRead的实现如下:
void Acceptor::handleRead()
{
  loop_->assertInLoopThread();
  InetAddress peerAddr;
  //FIXME loop until no more
  int connfd = acceptSocket_.accept(&peerAddr);
  if (connfd >= 0)
  {
    // string hostport = peerAddr.toIpPort();
    // LOG_TRACE << "Accepts of " << hostport;
    if (newConnectionCallback_)//TcpServer 中完成bind
    {
      newConnectionCallback_(connfd, peerAddr);
    }
    else
    {
      sockets::close(connfd);
    }
  }
  else
  {
    LOG_SYSERR << "in Acceptor::handleRead";
    // Read the section named "The special problem of
    // accept()ing when you can't" in libev's doc.
    // By Marc Lehmann, author of livev.
    if (errno == EMFILE)
    {
      ::close(idleFd_);
      idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL);
      ::close(idleFd_);
      idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
    }
  }
}


解释:每当收到一个连接,就执行一遍handleRead(),注意此时仍然在主线程中。接着通过newConnectionCallback_()执行TcpConnection::newConnection(),创建一个新的连接:
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{
  loop_->assertInLoopThread();
  EventLoop* ioLoop = threadPool_->getNextLoop();
  char buf[32];
  snprintf(buf, sizeof buf, ":%s#%d", hostport_.c_str(), nextConnId_);
  ++nextConnId_;
  string connName = name_ + buf;

  LOG_INFO << "TcpServer::newConnection [" << name_
           << "] - new connection [" << connName
           << "] from " << peerAddr.toIpPort();
  InetAddress localAddr(sockets::getLocalAddr(sockfd));
  // FIXME poll with zero timeout to double confirm the new connection
  // FIXME use make_shared if necessary
  TcpConnectionPtr conn(new TcpConnection(ioLoop,
                                          connName,
                                          sockfd,
                                          localAddr,
                                          peerAddr));
  connections_[connName] = conn;
  conn->setConnectionCallback(connectionCallback_);
  conn->setMessageCallback(messageCallback_);
  conn->setWriteCompleteCallback(writeCompleteCallback_);
  conn->setCloseCallback(
      boost::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe
  ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));
}


此函数,个人认为是整个muduo的精华的所在,即one loop per thread。注意两句代码:
EventLoop* ioLoop = threadPool_->getNextLoop();和
conn->setCloseCallback(
      boost::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe
  ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));
这两句完成了round-robin算法分发连接,以及对该连接在分发到的线程进行收发数据。

你可能感兴趣的:(muduo,开源阅读笔记)