【Flamingo 学习 1--底层框架启动流程】

ChatServer 初始化过程

创建一个全局的 EventLoop

1.创建事件fd–createWakeupfd

系统实现方法状态
windows使用两个socket实现FIONBIO
linuxeventID实现EFD_NONBLOCK | EFD_CLOEXEC

2.创建一个内部Channel m_wakeupChannel

m_wakeupChannel的主要作用是唤醒EventLoop的轮询器(m_poller->poll),当轮询器在等待事件时,可以使loop及时运行下去,不至于一直等待,直到等待时间结束才去做事。

  • 为m_wakeupChannel设置读回调
  • 设置这个m_wakeupChannel 为可读状态

单例 ChatServer初始化

1.创建一个TcpServer,它包含一个m_acceptor

  • m_acceptor包含一个m_acceptChannel,m_acceptChannel的setReadCallback函数是Acceptor::handleRead,这个函数里面有正真的accept
m_acceptChannel.setReadCallback(std::bind(&Acceptor::handleRead, this));
Acceptor::handleRead中包含正真的accept
int connfd = m_acceptSocket.accept(&peerAddr);
  • m_acceptor setNewConnectionCallback(TcpServer::newConnection),当有新的连接到来时,程式会使用到TcpServer::newConnection,在这里产生链接对象
m_acceptor->setNewConnectionCallback(std::bind(&TcpServer::newConnection, ...)
TcpServer::newConnection 包含
TcpConnectionPtr conn(new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr));

2.TcpServer 设置 setConnectionCallback

  • 设置回调ChatServer::onConnected,当链接成功,将会产生一个业务层链接ChatSession,它会与TcpConnection的对象进行绑定
 m_server->setConnectionCallback(std::bind(&ChatServer::onConnected, this, std::placeholders::_1));

3.TcpServer start 创建线程池

  • 线程池init,设置线程数量,设置主事件循环
  • 线程池start,创建线程,为每个线程分配eventLoop,创建线程的时候,一个一个创建,一个运行成功后,再创建下一个
  • 线程池创建完成之后,将Acceptor::listen的放入loop中执行,m_acceptChannel变为可读状态,loop中执行Acceptor::handleRead()

主事件循环启动 g_mainLoop.loop()

  • 用轮询器找到active的channel,并对其事件进行处理
  • 处理其他的任务
void EventLoop::loop()
{
	//LOGI("EventLoop::loop, begin...");
    //assert(!looping_);
    assertInLoopThread();//get current thread id
    m_looping = true;
    m_quit = false;  // FIXME: what if someone calls quit() before loop() ?
    LOGI("EventLoop 0x%x  start looping", this);
	LOGI("EventLoop eventId is %d", this);
	LOGI("EventLoop current threadId is %d", this->getThreadID());
    while (!m_quit)
    {
        m_timerQueue->doTimer(); //处理到期的定时器并删除

        m_activeChannels.clear();
        m_pollReturnTime = m_poller->poll(kPollTimeMs, &m_activeChannels); //找到active的channel
        //if (Logger::logLevel() <= Logger::TRACE)
        //{
        printActiveChannels(); //打印出来
        //}
        ++m_iteration;
        // TODO sort channel by priority
        m_eventHandling = true;
        for (const auto& it : m_activeChannels)  //对IO事件进行处理
        {
            currentActiveChannel_ = it;
            currentActiveChannel_->handleEvent(m_pollReturnTime);
        }
        currentActiveChannel_ = nullptr;
        m_eventHandling = false;
        doOtherTasks();                       //对其他事件进行处理    

        if (m_frameFunctor)
        {
            m_frameFunctor();
        }
    }

    LOGD("EventLoop 0x%0x stop looping", this);
    m_looping = false;

    std::ostringstream oss;
    oss << std::this_thread::get_id();
    std::string stid = oss.str();
    LOGI("Exiting loop, EventLoop object: 0x%x , threadID: %s", this, stid.c_str());
}

eventfd 轮询器唤醒机制
如果将超时时间设置为0,在没有任何网络IO事件和其他任务需要处理的情况下,这些工作线程实际上会空转,白白浪费了CPU时间片,如果将超时时间设置为大于0,则在没有网络IO事件但是主线程中有其他任务需要处理时,poll,epoll_wait和select等函数会在挂起指定时间后才能返回,导致handle_other_things中的任务不能及时执行。

对于这种问题来说,如果没有网络IO事件和其他任务要处理,那么这些工作线程最好直接挂起而不是空转;如果有其他任务要处理,那么这些工作线程要能立刻处理这些任务,而不是在poll,select和epoll_wait函数挂起指定事件后才处理其他任务。

解决方案是,对于poll,select和epoll_wait仍然会设置超时时间,但是对于handle_other_things函数,采取一种特殊的唤醒策略。

以Linux的epoll_wait为例,不管在epollfd上有没有socket fd,都会为epollfd挂载一个特殊的fd,这个fd被称为wakeup fd(唤醒fd)。当我们有其他任务要处理时,向这个唤醒fd上随便写入1字节的内容,这个唤醒fd就会立即变成可读的,epoll_wait函数会立即被唤醒返回,接下来就可以马上执行handle_other_thing函数了。

ChatServer事务处理

client连接上来

  1. m_poller->poll检测到m_acceptor的变化,执行m_acceptor的回调函数 TcpServer::newConnection
  2. 创建TcpConnection channel
TcpConnection channel注册的接口注册函数名称函数定义位置
TcpConnection::handleReadsetReadCallbackChatSession::onRead(m_messageCallback)
TcpConnection::handleWritesetWriteCallbackTCPserver m_writeCompleteCallback
TcpConnection::handleClosesetCloseCallbackTcpConnection::handleClose
TcpConnection::handleErrorsetErrorCallbackTcpConnection::handleClose
  1. 创建一个TcpConnection
TcpConnection注册的接口注册函数名称函数定义位置
m_connectionCallbacksetConnectionCallback(&ChatServer::onConnected)ChatServer-》TcpServer-》TcpConnection
m_messageCallbacksetMessageCallback(TcpServer ::m_messageCallback)ChatSession::onRead
m_writeCompleteCallbacksetWriteCompleteCallbackTCPserver m_writeCompleteCallback
TcpServer::removeConnectionsetCloseCallbackTcpServer::removeConnection
  1. 在IO线程中使 TcpConnection::connectEstablished
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值