muduo源码剖析--Thread/EventLoopThread/EventLoopThreadPool

文章介绍了muduo网络库中的基础线程类Thread,包括线程的启动、回收以及线程ID的获取。Thread类封装了C++11的std::thread,并提供了线程回调函数。此外,文章还讨论了EventLoopThread类,它是将线程与事件循环绑定在一起的类,用于执行子Reactor模式。EventLoopThread在线程中创建并运行EventLoop,支持上层的初始化回调。最后,文章提到了EventLoopThreadPool类,这是一个线程池,可以创建多个EventLoop并进行轮询分配任务。

Thread类

muduo网络库的基础线程类,封装了线程的基本操作。

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() { return started_; }
    pid_t tid() const { return tid_; } 			
    const std::string &name() const { return name_; } //获取线程名

    static int numCreated() { return numCreated_; } //获取创建线程的个数

private:
    void setDefaultName();

    bool started_;
    bool joined_;
    std::shared_ptr<std::thread> thread_; //这里采取的是c11提供的线程类
    pid_t tid_;       // 在线程创建时再绑定
    ThreadFunc func_; // 线程回调函数
    std::string name_;
    static std::atomic_int numCreated_;
};

构造函数:

Thread::Thread(ThreadFunc func, const std::string &name)
    : started_(false)
    , joined_(false)
    , tid_(0)
    , func_(std::move(func))  //c11移动构造
    , name_(name)
{
    setDefaultName();
}
//若未设置初始名字,则起一个默认的名字
void Thread::setDefaultName()
{
    int num = ++numCreated_;
    if (name_.empty())
    {
        char buf[32] = {0};
        snprintf(buf, sizeof buf, "Thread%d", num);
        name_ = buf;
    }
}

开启线程:

void Thread::start()                                                        // 一个Thread对象 记录的就是一个新线程的详细信息
{
    started_ = true;
    sem_t sem;
    //这里直接使用信号量,muduo源码采取的是互斥锁加条件变量实现
    sem_init(&sem, false, 0);                                               // false指的是 不设置进程间共享
    // 开启线程
    thread_ = std::shared_ptr<std::thread>(new std::thread([&]() {
        tid_ = CurrentThread::tid();                                        // 获取线程的tid值
        sem_post(&sem); //用于唤醒下面的sem_wait()
        func_();                                                            // 开启一个新线程 专门执行该线程函数
    }));

    // 这里必须等待获取上面新创建的线程的tid值
    sem_wait(&sem);
}

回收线程:

// C++ std::thread 中join()和detach()的区别:https://blog.nowcoder.net/n/8fcd9bb6e2e94d9596cf0a45c8e5858a
void Thread::join()
{
    joined_ = true;
    thread_->join();
}

释放资源:

Thread::~Thread()
{
    if (started_ && !joined_)
    {
        thread_->detach();          // thread类提供了设置分离线程的方法 线程运行后自动销毁(非阻塞)
    }
}

EventLoopThread类

将Thred与EventLoop绑定在一起的类,用于执行子Reactor模式,一个EventLoop对象在一个线程中执行。

class EventLoop;

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:
    void threadFunc();

    EventLoop *loop_;	//绑定的loop对象
    bool exiting_;
    Thread thread_;		//绑定的线程类
    std::mutex mutex_;             // 互斥锁
    std::condition_variable cond_; // 条件变量
    ThreadInitCallback callback_;
};

构造函数:

	EventLoopThread::EventLoopThread(const ThreadInitCallback &cb,
                                 const std::string &name)
    : loop_(nullptr)	 //初始化为空,在线程函数里面进行初始化
    , exiting_(false)
    , thread_(std::bind(&EventLoopThread::threadFunc, this), name) 	//初始化绑定的线程,及其要执行的回调函数
    , mutex_()
    , cond_()
    , callback_(cb)
{
}


开启一个事件循环,事件循环在线程中执行

EventLoop *EventLoopThread::startLoop()
{
    thread_.start(); // 启用底层线程Thread类对象thread_中通过start()创建的线程

    EventLoop *loop = nullptr;
    {
        std::unique_lock<std::mutex> lock(mutex_);
        while(loop_ == nullptr) //阻塞,直到在线程函数中唤醒
        {
            cond_.wait(lock);
        }
        loop = loop_;
    }
    return loop;
}

线程函数,在创建的线程中执行上层的初始化回调,并创建属于这个线程的EventLoop对象,随后通过startLoop方法将这个对象返回给主调线程

// 下面这个方法 是在单独的新线程里运行的
void EventLoopThread::threadFunc()
{
    EventLoop loop; // 创建一个独立的EventLoop对象 和上面的线程是一一对应的 级one loop per thread

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

    {
        std::unique_lock<std::mutex> lock(mutex_);
        loop_ = &loop;
        cond_.notify_one();
    }
    loop.loop();    // 执行EventLoop的loop() 开启了底层的Poller的poll(),阻塞状态
    std::unique_lock<std::mutex> lock(mutex_);
    loop_ = nullptr; //意味着事件循环已经结束
}

释放:

EventLoopThread::~EventLoopThread()
{
    exiting_ = true;
    if (loop_ != nullptr)
    {
        loop_->quit(); //退出循环
        thread_.join(); //回收线程
    }
}

EventLoopThreadPool类

EventLoopThread线程池类,用于创建多个loop对象和thread类绑定的对象,主Loop(主Reactor)采取轮询的操作下发channel给子loop(子Reactor)。

class EventLoop;
class EventLoopThread;

class EventLoopThreadPool : noncopyable
{
public:
    using ThreadInitCallback = std::function<void(EventLoop *)>;

    EventLoopThreadPool(EventLoop *baseLoop, const std::string &nameArg);
    ~EventLoopThreadPool();

    void setThreadNum(int numThreads) { numThreads_ = numThreads; }  //设置线程个数

    void start(const ThreadInitCallback &cb = ThreadInitCallback());

    // 如果工作在多线程中,baseLoop_(mainLoop)会默认以轮询的方式分配Channel给subLoop
    EventLoop *getNextLoop();

    std::vector<EventLoop *> getAllLoops();

    bool started() const { return started_; }
    const std::string name() const { return name_; }

private:
    EventLoop *baseLoop_; // 用户使用muduo创建的loop 如果线程数为1 那直接使用用户创建的loop 否则创建多EventLoop
    std::string name_;
    bool started_;
    int numThreads_;  //线程池中线程的个数
    int next_; // 轮询的下标
    std::vector<std::unique_ptr<EventLoopThread>> threads_;	 
    std::vector<EventLoop *> loops_;	//存放所有loop对象的数组(为了轮询得到子loop)
};

构造函数:
主要就是初始化baseloop对象(主Reactor)

EventLoopThreadPool::EventLoopThreadPool(EventLoop *baseLoop, const std::string &nameArg)
    : baseLoop_(baseLoop)
    , name_(nameArg)
    , started_(false)
    , numThreads_(0)
    , next_(0)
{
}

start()方法初始化线程池并执行

void EventLoopThreadPool::start(const ThreadInitCallback &cb)
{
    started_ = true;

//多Reactor方式,一个主Reactor多个子Reactor
    for(int i = 0; i < numThreads_; ++i)  //循环创建EventLoopThread线程类
    {
        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());                           // 底层创建线程 绑定一个新的EventLoop 并返回该loop的地址
    }


//单Reactor模式
    if(numThreads_ == 0 && cb)                                      // 整个服务端只有一个线程运行baseLoop
    {
        cb(baseLoop_);
    }
}

getNextLoop()方法实现具体的轮询操作

// 如果工作在多线程中,baseLoop_(mainLoop)会默认以轮询的方式分配Channel给subLoop
EventLoop *EventLoopThreadPool::getNextLoop()
{
    EventLoop *loop = baseLoop_;    // 如果只设置一个线程 也就是只有一个mainReactor 无subReactor 那么轮询只有一个线程 getNextLoop()每次都返回当前的baseLoop_

    if(!loops_.empty())             // 通过轮询获取下一个处理事件的loop
    {
        loop = loops_[next_];
        ++next_;
        if(next_ >= loops_.size())
        {
            next_ = 0;
        }
    }

    return loop;
}

getAllLoops()获取创建的所有loop对象

std::vector<EventLoop *> EventLoopThreadPool::getAllLoops()
{
    if(loops_.empty())
    {
        return std::vector<EventLoop *>(1, baseLoop_);
    }
    else
    {
        return loops_;
    }
}

释放操作:什么都不做,由于loop对象在子线程中创建的是栈对象,所以不需要释放,且线程类EventLoopThreadPool对象由智能指针管理也无需释放。

EventLoopThreadPool::~EventLoopThreadPool()
{
    // Don't delete loop, it's stack variable
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值