muduo::EventLoop分析

來源:互聯網
上載者:User

標籤:muduo   eventloop   reactor   

EventLoop是整個Reactor的核心。其類圖如下:

one loop per thread意味著每個線程只能有一個EventLoop對象,用變數

__thread EventLoop* t_loopInThisThread = 0;

表示,在建立EventLoop對象時將t_loopInThisThread賦值,以後再建立時就可以檢查這個變數,如果已經賦值就說明當前線程已經建立過EventLoop對象了。線程調用靜態函數EventLoop::getEventLoopOfCurrentThread就可以獲得當前線程的EventLoop對象的指標了。

EventLoop有許多變數,幾個bool變數,looping_:是否正在執行loop迴圈;quit_:是否已經調用quit()函數退出loop迴圈;eventHandling是否正在處理event事件;callingPendingFunctors是否正在調用pendingFunctors_的函數對象。

其他變數,poller_是用來調用pool或epool的,activeChannels_記錄這啟用事件的集合,currentActiveChannel_是當前正在處理的channel事件,pendingFunctors_是當前線程要執行任務的集合。可以在loop()函數中看到這一點:

void EventLoop::loop()//EventLoop在這裡迴圈{  assert(!looping_);  assertInLoopThread();  looping_ = true;  quit_ = false;  // FIXME: what if someone calls quit() before loop() ?  LOG_TRACE << "EventLoop " << this << " start looping";  while (!quit_)  {    activeChannels_.clear();//清空啟用事件集合    pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);//pool_wait或epoll_wait。阻塞在這裡    ++iteration_;    if (Logger::logLevel() <= Logger::TRACE)    {      printActiveChannels();    }    // TODO sort channel by priority    eventHandling_ = true;    for (ChannelList::iterator it = activeChannels_.begin();        it != activeChannels_.end(); ++it)    {      currentActiveChannel_ = *it;      currentActiveChannel_->handleEvent(pollReturnTime_);//事件處理I/O    }    currentActiveChannel_ = NULL;    eventHandling_ = false;    doPendingFunctors();  }  LOG_TRACE << "EventLoop " << this << " stop looping";  looping_ = false;}

線程在poller_->poll等待監聽事件的到來,當poller_->poll返回後,監聽到的事件放到了activeChannel中,隨後一一處理啟用事件。

最後面調用doPendingFunctors()是執行pendingFunctors_中的任務。

void EventLoop::doPendingFunctors()//執行任務隊列中的任務{  std::vector<Functor> functors;  callingPendingFunctors_ = true;  {  MutexLockGuard lock(mutex_);//盡量讓臨界區小  functors.swap(pendingFunctors_);  }  for (size_t i = 0; i < functors.size(); ++i)  {    functors[i]();  }  callingPendingFunctors_ = false;}

EventLoop的owner線程除了等待poll、執行poll返回的啟用事件,還可以處理一些其他任務,例如調用某一個回呼函數,處理其他EventLoop對象的,調用void EventLoop::runInLoop(const Functor& cb)即可讓EventLoop的owner線程執行cb函數。

void EventLoop::runInLoop(const Functor& cb)//可以誇線程調用{  if (isInLoopThread())//當前線程是ower線程則立即執行,否則放到ower線程的任務隊列,非同步執行  {    cb();  }  else  {    queueInLoop(cb);  }}void EventLoop::queueInLoop(const Functor& cb){  {  MutexLockGuard lock(mutex_);  pendingFunctors_.push_back(cb);  }//不是EventLoop的owner線程,或者是當前線程,但是正在執行任務隊列中的任務  if (!isInLoopThread() || callingPendingFunctors_)  {    wakeup();//喚醒owner線程  }}

如果時EventLoop的owner線程,會調用runInLoop會立即執行回呼函數cb,否則會把回呼函數放到任務隊列(其即時vector),即調用queueInLoop函數。如果不是當前線程調用,或者正在執行pendingFunctors_中的任務,都要喚醒EventLoop的owner線程,讓其執行pendingFunctors_中的任務。如果正在執行pendingFunctors_中的任務,添加新任務後不會執行新的任務,因為functors.swap(pendingFunctors_)後,執行的時functors中的任務。

這裡的喚醒wakeup()用了eventfd。這是2.6核心新增的一個技術。

#include <sys/eventfd.h>  int eventfd(unsigned int initval, int flags);  

建立一個eventfd的fd後,就可以對它進行read、write等操作。eventfd相當於一個計數器,read以後計數器清零,write遞增計數器;fd可以進行如下操作:select(poll、epoll)、close操作。

EventLoop中的wakeupFd_就是eventfd,wakeupChannel_和wakeupFd_相關聯,EventLoop關注了wakeupChannel_的讀事件,當要喚醒(即poller_->poll)時,寫wakeupFd_即可。

void EventLoop::wakeup()//wakeupFd寫,喚醒讀wakeupFd的線程{  uint64_t one = 1;  ssize_t n = sockets::write(wakeupFd_, &one, sizeof one);  if (n != sizeof one)  {    LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8";  }}

EventLoop中還有定時器,可以在某一時刻(runAt),未來多久(runAfter),每隔多久(runEvery)執行某一函數。定時用到了TimerQueue,稍後分析它。

TimerId EventLoop::runAt(const Timestamp& time, TimerCallback&& cb){  return timerQueue_->addTimer(std::move(cb), time, 0.0);}TimerId EventLoop::runAfter(double delay, TimerCallback&& cb){  Timestamp time(addTime(Timestamp::now(), delay));  return runAt(time, std::move(cb));}TimerId EventLoop::runEvery(double interval, TimerCallback&& cb){  Timestamp time(addTime(Timestamp::now(), interval));  return timerQueue_->addTimer(std::move(cb), time, interval);}

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

muduo::EventLoop分析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.