muduo线程的启动

哈罗_aae9 · · 1015 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

上篇说了多线程处理的概述,这篇说说具体实现。

muduo的多线程是由线程池中启动的。线程池类EventLoopThreadPool在TcpServer类中创建一个心得实例。发现在muduo中,各种类的关系基本上引用和包含即组合关系,很少有派生关系的,没有继承关系就没有虚函数的应用了。

可能陈硕觉得继承关系比较复杂,耦合度太高,破坏整体设计。但是我觉得muduo中那么多不同种类的智能指针,还有基于boost或std的函数绑定,本身就够复杂的了。所以我打算有时间用c语言来改写一下muduo,把那些智能指针,函数绑定等弱化,只关注网络框架本身。不过说实话,muduo本身就是基于C++的,用智能指针和函数绑定很正常,而且人家还用得非常到位。所以要想往C++方面发展,还是得精通上面的知识。我本身是搞C++,而且搞了很久,而且决定一直搞下去。不过在接触c项目,脚本语言,还有现代网络并发语言golang之后,还是觉得用C++写项目开发效率太低了,而且很难驾驭,指针就是一个雷区。精通C++的时间与其收获性价比是很低的,所以我决定以后不再画太多的时间在C++上,对于C++项目,我只是关注其框架本身。

好了废话少说。EventLoopThreadPool的start在TcpServer的start中调用,他会创建n个线程并启动,n是EventLoopThreadPool的成员变量,可以配置,也可以是0个。每个线程是EventLoopThread的实例。而EventLoopThread有个组合对象Thread,他才是线程创建和启动真正的地方。代码如下:

void TcpServer::start()
{
  if (started_.getAndSet(1) == 0)
  {
    threadPool_->start(threadInitCallback_);

    assert(!acceptor_->listenning());
    loop_->runInLoop(
        std::bind(&Acceptor::listen, get_pointer(acceptor_)));
  }
}
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(std::unique_ptr<EventLoopThread>(t));
    loops_.push_back(t->startLoop());
  }
  if (numThreads_ == 0 && cb)
  {
    cb(baseLoop_);
  }
}
void Thread::start()
{
  assert(!started_);
  started_ = true;
  // FIXME: move(func_)
  detail::ThreadData* data = new detail::ThreadData(func_, name_, &tid_, &latch_);
  if (pthread_create(&pthreadId_, NULL, &detail::startThread, data))
  {
    started_ = false;
    delete data; // or no delete?
    LOG_SYSFATAL << "Failed in pthread_create";
  }
  else
  {
    latch_.wait();
    assert(tid_ > 0);
  }
}

Thread的线程函数已经绑定在了EventLoopThread::threadFunc里,这个是在EventLoopThread构造函数是初始化的。代码如下:

void EventLoopThread::threadFunc()
{
  EventLoop loop;

  if (callback_)
  {
    callback_(&loop);
  }

  {
    MutexLockGuard lock(mutex_);
    loop_ = &loop;
    cond_.notify();
  }

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

这里有个问题是,主线程会加入新线程的loop实例,而这个loop实例又是在线程的线程函数里创建的。所以很显然主线程和新线程有个同步的过程,并且多个新线程之间有临界区的问题。这些是用条件变量pthread_cond_t和互斥变量mutext来实现的。

新线程线程函数在栈上申明一个EventLoop对象之后,便通知主线程了。这使得主线程返回,而新线程函数中loop开始运作循环了。那么主线程又是如何跨线程调用新线程的函数的呢?这个下篇再说。


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:哈罗_aae9

查看原文:muduo线程的启动

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1015 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传