muduo::EventLoopThread、EventLoopThreadPool分析

來源:互聯網
上載者:User

EventLoopThread EventLoopThreadPool

muduo的並行存取模型為one loop per thread+ threadpool。為了方便使用,muduo封裝了EventLoop和Thread為EventLoopThread,為了方便使用線程池,又把EventLoopThread封裝為EventLoopThreadPool。 EventLoopThread

任何一個線程,只要建立並運行了EventLoop,就是一個IO線程。
EventLoopThread類就是一個封裝了的IO線程。
EventLoopThread的工作流程為:
1、在主線程(暫且這麼稱呼)建立EventLoopThread對象。
2、主線程調用EventLoopThread.start(),啟動EventLoopThread中的線程(稱為IO線程),這是主線程要等待IO線程建立完成EventLoop對象。
3、IO線程調用threadFunc建立EventLoop對象。通知主線程已經建立完成。
4、主線程返回建立的EventLoop對象。

EventLoopThread.h

class EventLoopThread : boost::noncopyable{ public:  typedef boost::function<void(EventLoop*)> ThreadInitCallback;  EventLoopThread(const ThreadInitCallback& cb = ThreadInitCallback(),                  const string& name = string());  ~EventLoopThread();  EventLoop* startLoop();//啟動本線程,返回本線程中的EventLoop private:  void threadFunc();  EventLoop* loop_;//本線程持有的EventLoop對象指標  bool exiting_;//是否已經退出  Thread thread_;//本線程  MutexLock mutex_;  Condition cond_;  ThreadInitCallback callback_;//回呼函數};

EventLoopThread.cc

EventLoopThread::EventLoopThread(const ThreadInitCallback& cb,                                 const string& name)  : loop_(NULL),    exiting_(false),    thread_(boost::bind(&EventLoopThread::threadFunc, this), name),//建立線程,在回呼函數建立EventLoop    mutex_(),    cond_(mutex_),    callback_(cb){}EventLoopThread::~EventLoopThread(){  exiting_ = true;  if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_.  {    // still a tiny chance to call destructed object, if threadFunc exits just now.    // but when EventLoopThread destructs, usually programming is exiting anyway.    loop_->quit();//退出loop迴圈    thread_.join();//等待線程退出  }}EventLoop* EventLoopThread::startLoop()//另一個線程在調用這個函數{  assert(!thread_.started());  thread_.start();//當前線程啟動,調用threadFunc()  {    MutexLockGuard lock(mutex_);    while (loop_ == NULL)    {      cond_.wait();//等待建立好當前IO線程    }  }  return loop_;}void EventLoopThread::threadFunc(){  EventLoop loop;//建立EventLoop對象。注意,在棧上  if (callback_)  {    callback_(&loop);  }  {    MutexLockGuard lock(mutex_);    loop_ = &loop;    cond_.notify();//通知startLoop  }  loop.loop();//會在這裡迴圈,直到EventLoopThread析構。此後不再使用loop_訪問EventLoop了  //assert(exiting_);  loop_ = NULL;}
EventLoopThreadPool

muduo的思想時eventLoop+thread pool,為了更方便使用,將EventLoopThread做了封裝。main reactor可以建立sub reactor,並發一些任務分發到sub reactor中去。

EventLoopThreadPool的思想比較簡單,用一個main reactor建立EventLoopThreadPool。在EventLoopThreadPool中將EventLoop和Thread綁定,可以返回EventLoop對象來使用EventLoopThreadPool中的Thread。

EventLoopThreadPool.h

class EventLoop;class EventLoopThread : boost::noncopyable{ public:  typedef boost::function<void(EventLoop*)> ThreadInitCallback;  EventLoopThread(const ThreadInitCallback& cb = ThreadInitCallback(),                  const string& name = string());  ~EventLoopThread();  EventLoop* startLoop();//啟動本線程,返回本線程中的EventLoop private:  void threadFunc();  EventLoop* loop_;//本線程持有的EventLoop對象指標  bool exiting_;//是否已經退出  Thread thread_;//本線程  MutexLock mutex_;  Condition cond_;  ThreadInitCallback callback_;//回呼函數};

EventLoopThreadPool.cc

EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg)  : baseLoop_(baseLoop),    name_(nameArg),    started_(false),    numThreads_(0),    next_(0){}EventLoopThreadPool::~EventLoopThreadPool(){  // Don't delete loop, it's stack variable}void EventLoopThreadPool::start(const ThreadInitCallback& cb){  assert(!started_);  baseLoop_->assertInLoopThread();  started_ = true;  for (int i = 0; i < numThreads_; ++i)  {    char buf[name_.size() + 32];    snprintf(buf, sizeof buf, "%s%d", name_.c_str(), i);    EventLoopThread* t = new EventLoopThread(cb, buf);    threads_.push_back(t);    loops_.push_back(t->startLoop());  }  if (numThreads_ == 0 && cb)  {    cb(baseLoop_);  }}EventLoop* EventLoopThreadPool::getNextLoop(){  baseLoop_->assertInLoopThread();  assert(started_);  EventLoop* loop = baseLoop_;//loops_為空白,則返回baseloop  if (!loops_.empty())//迴圈分配  {    // round-robin    loop = loops_[next_];    ++next_;    if (implicit_cast<size_t>(next_) >= loops_.size())    {      next_ = 0;    }  }  return loop;}EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode){  baseLoop_->assertInLoopThread();  EventLoop* loop = baseLoop_;  if (!loops_.empty())  {    loop = loops_[hashCode % loops_.size()];//根據hashCode分配  }  return loop;}std::vector<EventLoop*> EventLoopThreadPool::getAllLoops(){  baseLoop_->assertInLoopThread();  assert(started_);  if (loops_.empty())  {    return std::vector<EventLoop*>(1, baseLoop_);  }  else  {    return loops_;  }}

可以寫個簡單的測試程式,建立一個EventLoopThreadPool,列印其中線程的ID和name。

#include <muduo/net/EventLoop.h>#include <muduo/net/EventLoopThread.h>#include <muduo/net/EventLoopThreadPool.h>#include <stdio.h>using namespace muduo;using namespace muduo::net;void runInThread(){    printf("runInThread(): name = %s, tid = %d\n",           CurrentThread::name(), CurrentThread::tid());}int main(){    printf("main(): pid = %d, tid = %d\n",           getpid(), CurrentThread::tid());    runInThread();    EventLoop loop;    EventLoopThreadPool loopThreadPool(&loop, "sub Reactor");    loopThreadPool.setThreadNum(5);    loopThreadPool.start();    for(int i=0; i<10; ++i)    {        EventLoop* loopFromPool=loopThreadPool.getNextLoop();        loopFromPool->runInLoop(runInThread);    }    sleep(3);    printf("exit main().\n");}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.