Muduo是 one loop per thread 模型的典范,其将EventLoop和thread封装成EventLoopThread,并且实现了一个简单的线程池来管理所有运行着loop的线程。
Thread
Thread是最基础的多线程表示。它封装了操作系统线程创建、管理、销毁等功能的类。在 Muduo 中,Thread类解绑了线程的创建和线程的启动,并保存了线程函数。
EventLoopThread
在解释 EventLoopThread之前,需要先理解 EventLoop。EventLoop是 Muduo 中事件循环的核心组件,它负责监听 I/O 事件、定时器事件等,并在这些事件发生时调用相应的回调函数。每个 EventLoop实例通常与一个线程关联,并在这个线程的事件循环中运行。
EventLoopThread是 Thread和 EventLoop的结合体。它封装了一个线程和一个运行在该线程上的 EventLoop实例。当创建一个 EventLoopThread对象时,它会创建一个新线程,并在这个线程中初始化并运行一个 EventLoop实例,而当EventLoopThread开始执行startLoop时,子线程才真正开始执行。
EventLoopThreadPool
EventLoopThreadPool是对多个 EventLoopThread的管理。它维护了一个 EventLoopThread的线程池,允许用户自己设置线程池的线程个数,在创建线程时同时生成每个线程的EventLoop。并且在TcpServer中有新连接到来时,通过轮训算法选择一个子线程。这对于处理大量并发连接或需要并行处理的任务非常有用。
源码
Thread.h
#include <thread>
#include "noncopyable.h"
#include <functional>
#include <atomic>
#include <string>
#include <memory>
class Thread : noncopyable
{
public:
// 若函数带返回值,则需要绑定器相关编程
using ThreadFunc = std::function<void()>;
// 构造函数不应被用于隐式类型转换
explicit Thread(ThreadFunc, const std::string &name = std::string());
~Thread();
void start();
void join();
bool started() const { return started_; }
pid_t tid() const { return tid_; }
const std::string &name() const { return name_; }
static int numCreated() { return numCreated_; }
private:
void setDefaultName();
std::shared_ptr<std::thread> pthread_; // 指针控制线程的开始时机
bool started_;
bool joined_; // 是普通的线程,主线程等待本线程执行完再继续。当前线程等待新线程执行完再返回
pid_t tid_;
ThreadFunc func_;
std::string name_;
static std::atomic_int numCreated_;
};
Thread.cc
#include "Thread.h"
#include "LogStream.h"
#include "CurrentThread.h"
#include <semaphore.h>
#include <iostream>
std::atomic_int Thread::numCreated_(0);
Thread::Thread(ThreadFunc func, const std::string &name)
: started_(false),
joined_(false),
tid_(0),
func_(std::move(func)), // 底层资源直接转移给func_
name_(name)
{
setDefaultName();
}
Thread::~Thread()
{
// 线程不在运行没必要操作
if(started_ && !joined_){ // join 和 detach 是线程必须的两种模式,必须选择其一
pthread_->detach(); // 守护线程,主线程结束的时候此线程自动结束
}
}
// 一个Thread对象就记录了一个新线程的详细信息
void Thread::start()
{
started_ = true;
sem_t sem;
sem_init(&sem, false, 0);
// 开启线程
pthread_ = std::make_shared<std::thread>([&](){
// 获取线程的tid值
tid_ = CurrentThread::tid();
//信号量+1
sem_post(&sem);
// 开启一个新线程,专门执行该线程函数
func_();
});
// 等待tid_有值
sem_wait(&sem);
}
void Thread::join()
{
joined_ = true;
pthread_->join();
}
void Thread::setDefaultName()
{
if (name_.empty())
{
name_ = "Thread" + std::to_string(++numCreated_);
}
}
EventLoopThread.h
#pragma once
#include "noncopyable.h"
#include "Thread.h"
#include <functional>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
class EventLoop;
// 绑定一个loop和thread,thread中创建loop
// one loop pre thread
class EventLoopThread : noncopyable
{
public:
using ThreadInitCallback = std::function<void(EventLoop *)>;
EventLoopThread(const ThreadInitCallback &cb = ThreadInitCallback(),
const std::string &name = std::string());
~EventLoopThread();
EventLoop *startLoop();
private:
// 线程函数,在其中创建loop
void threadFunc();
EventLoop *loop_;
bool exiting_;
Thread thread_;
std::mutex mutex_;
std::condition_variable cond_;
ThreadInitCallback callback_;
};
EventLoopThread.cc
#include "EventLoopThread.h"
#include "EventLoop.h"
EventLoopThread::EventLoopThread(const ThreadInitCallback &cb,
const std::string &name)
: loop_(nullptr)
, exiting_(false)
, thread_(std::bind(&EventLoopThread::threadFunc, this), name)
, mutex_()
, cond_()
, callback_(cb)
{
}
EventLoopThread::~EventLoopThread()
{
exiting_ = true;
if (loop_ != nullptr)
{
loop_->quit();
thread_.join(); // ?
}
}
EventLoop *EventLoopThread::startLoop()
{
thread_.start(); // 启动底层新线程,启动threadFunc
EventLoop *loop = nullptr; // 此时还未在新线程生成新loop
{
std::unique_lock<std::mutex> ulock(mutex_);
while (loop_ == nullptr)
{
cond_.wait(ulock);
}
loop = loop_;
}
return loop;
}
// 本方法在新线程中执行
void EventLoopThread::threadFunc()
{
// 新线程中创建一个独立的EventLoop,和thread一一对应
// one loop pre thread
EventLoop loop;
if (callback_)
{
// 执行上级准备的回调
callback_(&loop);
}
{
std::unique_lock<std::mutex> ulock(mutex_);
loop_ = &loop;
cond_.notify_one();
}
loop.loop();// EventLoop *EventLoopThread::loop() => Poller.poll 开始监听、处理读写
//当前线程(是新线程)进入阻塞状态
// loop()返回之后:
std::unique_lock<std::mutex> ulock(mutex_);
loop_ = nullptr;
}
EventLoopThreadPool.h
#pragma once
#include "noncopyable.h"
#include <functional>
#include <string>
#include <memory>
#include <vector>
class EventLoop;
class EventLoopThread;
class EventLoopThreadPool : noncopyable
{
public:
using ThreadInitCallback = std::function<void(EventLoop *)>; // 初始化EventLoopThread之后的回调函数
EventLoopThreadPool(EventLoop *baseLoop, const std::string &nameArg);
~EventLoopThreadPool();
void setThreadNum(int numThreads) { numThreads_ = numThreads; }
void start(const ThreadInitCallback &cb = ThreadInitCallback());
// valid after calling start()
/// round-robin
// 如果在多线程中,baseLoop_默认以轮询的方式分配channel给subloop
EventLoop *getNextLoop();
/// with the same hash code, it will always return the same EventLoop
// 用不到
EventLoop *getLoopForHash(size_t hashCode);
// 用不到
std::vector<EventLoop *> getAllLoops();
bool started() const
{
return started_;
}
const std::string &name() const
{
return name_;
}
private:
EventLoop *baseLoop_; // 父loop
std::string name_;
bool started_;
int numThreads_;
int next_;
std::vector<std::unique_ptr<EventLoopThread>> threads_;
std::vector<EventLoop *> loops_;
};
EventLoopThreadPool.cc
#include "EventLoopThreadPool.h"
#include "EventLoopThread.h"
#include "LogStream.h"
EventLoopThreadPool::EventLoopThreadPool(EventLoop *baseLoop, const std::string &nameArg)
: baseLoop_(baseLoop), name_(nameArg), started_(false), numThreads_(0), next_(0)
{
LOG_DEBUG << "EventLoopThreadPool::EventLoopThreadPool():" << nameArg;
}
EventLoopThreadPool::~EventLoopThreadPool()
{
}
void EventLoopThreadPool::start(const ThreadInitCallback &cb)
{
started_ = true;
LOG_DEBUG << "EventLoopThreadPool::start(const ThreadInitCallback &cb)" << " numThreads_ = " << numThreads_ << " cb:" << (cb != 0);
for (int i = 0; i < numThreads_; ++i)
{
std::string name = name_ + std::to_string(i);
EventLoopThread *t = new EventLoopThread(cb, name);
threads_.emplace_back(std::unique_ptr<EventLoopThread>(t));
loops_.emplace_back(t->startLoop());// 底层创建线程,绑定一个新的EventLoop,并返回该loop的地址
}
// 整个服务只有一个线程,运行着baseLoop
if (numThreads_ == 0 && cb)
{
LOG_DEBUG;
cb(baseLoop_);
}
// LOG_DEBUG << "end";
}
EventLoop *EventLoopThreadPool::getNextLoop()
{
LOG_DEBUG <<"EventLoopThreadPool::getNextLoop() loops_.size()=" << loops_.size();
EventLoop *loop = baseLoop_;
if(!loops_.empty()){
loop = loops_[next_];
++next_;
if(next_ >= loops_.size()){
next_ = 0;
}
}
return loop;
}
EventLoop *EventLoopThreadPool::getLoopForHash(size_t hashCode)
{
EventLoop* loop = baseLoop_;
if(!loops_.empty()){
loop = loops_[hashCode % loops_.size()]; // 循环提供loops中的loop
}
return loop;
}
std::vector<EventLoop *> EventLoopThreadPool::getAllLoops()
{
if (loops_.empty())
{
return std::vector<EventLoop *>(1, baseLoop_);
}
else
{
return loops_;
}
}