muduo线程的启动

作者: 哈罗_aae9 | 来源:发表于2018-08-03 16:10 被阅读6次

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

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开始运作循环了。那么主线程又是如何跨线程调用新线程的函数的呢?这个下篇再说。

相关文章

  • muduo线程的启动

    上篇说了多线程处理的概述,这篇说说具体实现。 muduo的多线程是由线程池中启动的。线程池类EventLoopTh...

  • muduo多线程的处理

    这几天详细读了muduo的网络处理部分,发现多线程处理是整个框架的精华。muduo是基于one loop per ...

  • C++线程池

    模仿muduo库,用C++写了个线程池Reuzel

  • c++操作系统类编程 - read list

    Concurrency C++ in Action Linux多线程服务端编程:使用muduo C++网络库 现代...

  • Muduo库设计(8)——多线程

    一、EventLoopThread类 首先Muduo看一下对于线程的封装,以及如何做到 one loop per ...

  • shared_ptr的线程安全

    读到muduo大大的网络编程,对shared_ptr到底哪部分是线程安全,哪部分不是线程安全的产生了一些疑问 1....

  • muduo中的reactor

    muduo使用的是reactor模式,关于muduo的其他内容不做过多赘述。此文作为自己阅读muduo源码的笔记,...

  • iOS 多线程-NSThread

    1. 创建和启动线程 创建、启动线程 2. 其他创建线程方式 创建线程后自动启动线程[NSThread detac...

  • 线程 NSThread

    NSThread 创建线程后自动启动线程 隐身创建并启动线程 让线程睡眠2秒(阻塞2秒) 启动线程进入就绪状态 -...

  • muduo-base部分Timestamp

    muduo::copyable

网友评论

    本文标题:muduo线程的启动

    本文链接:https://www.haomeiwen.com/subject/aogyvftx.html