Muduo库源码剖析(五)——Thread相关类

33 篇文章 2 订阅
15 篇文章 6 订阅

Thread类

具体重点见代码注释

// Thread.h
#pragma once

#include "noncopyable.h"

#include <functional>
#include <thread>
#include <memory>
#include <unistd.h>
#include <string>
#include <atomic>


class Thread : noncopyable
{
public:
    using ThreadFunc = std::function<void()>;
    
    explicit Thread(ThreadFunc, const std::string &name = std::string());
    ~Thread();

    void start();
    // Blocks the current thread until the thread identified by *this finishes its execution.
    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();

    bool started_;
    // joined_ == true,表示必须等待线程执行工作函数后才能接下去的工作
    bool joined_; 
    std::shared_ptr<std::thread> thread_;
    pid_t tid_;
    ThreadFunc func_;
    std::string name_;
    static std::atomic_int numCreated_; // 记录产生线程的个数,给线程起名用的
};

// Thread.cc
#include "Thread.h"
#include "CurrentThread.h"

#include <semaphore.h>

// 原子变量初始化最好要这么写,不要写成 = 0,会报错,因为拷贝赋值被deleted
std::atomic_int Thread::numCreated_(0); 
// 定义中不用再次出现默认值
Thread::Thread(ThreadFunc func, const std::string &name)
    : started_(false)
    , joined_(false)
    , tid_(0)
    , func_(std::move(func))
    , name_(name)
{
    setDefaultName();
}
Thread::~Thread()
{
    if(started_ && !joined_)
    {
        thread_->detach(); // 设置分离线程,作为后台线程了
    }
}

// 一个Thread对象,记录的就是一个新线程的详细信息
void Thread::start()
{
    started_ = true;
    sem_t sem;
    sem_init(&sem, false, 0);

    // 开启线程
    thread_ = std::shared_ptr<std::thread>(new std::thread([&](){
        // 获取线程的tid值
        tid_ = CurrentThread::tid();
        sem_post(&sem); // 信号量资源 + 1
        // 执行新线程的工作函数
        func_();
    }));
    
    // 这里必须等待获取上面新建的tid值
    // 防止上面tid_还是空的
    sem_wait(&sem);
}

void Thread::join()
{
    joined_ = true;
    thread_->join();
}

void Thread::setDefaultName()
{
    int num = ++numCreated_;
    if(name_.empty())
    {
        char buf[32] = {0};
        snprintf(buf, sizeof buf, "Thread%d", num);
        name_ = buf;
    }
}

EventLoopThread类

该类的主要功能是实现 one loop per thread中,loopthread的一对一绑定,是muduo库的一大亮点。

// EventLoopThread.h
#pragma once

#include "noncopyable.h"
#include "Thread.h"

#include <functional>
#include <mutex>
#include <condition_variable>
#include <string>

class EventLoop;

class EventLoopThread : noncopyable
{
public:
    using ThreadInitCallback = std::function<void(EventLoop*)>;
    // 这个类对象是由 EventLoopThread::start() 创建
    EventLoopThread(const ThreadInitCallback &cb = ThreadInitCallback(),
        const std::string &name = std::string());
    ~EventLoopThread();

    EventLoop* startLoop();
private:
    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(); // 启动底层的新线程
    EventLoop *loop = nullptr;
    {
        std::unique_lock<std::mutex> lock(mutex_);
        // 用while防止被其他线程抢走了,确保资源存在
        while(loop_ == nullptr) // 等待对应的 EventLoop创建
        {
            cond_.wait(lock);
        }
        loop = loop_;
    }
    return loop;
}

// 在单独的新线程里运行,即thread_.start()内的func()
void EventLoopThread::threadFunc()
{
    // 创建一个独立的eventloop,和上面线程一一对应
    // one loop per thread
    // 栈上分配
    EventLoop loop; 

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

    {
        std::unique_lock<std::mutex> lock(mutex_);
        loop_ = &loop;
        cond_.notify_one();
    }

    loop.loop(); // EventLoop.loop => Poller.poll
    // loop 内 quit被置为true,退出loop才会到下面代码
    std::unique_lock<std::mutex> lock(mutex_);
    loop_ = nullptr;
}

EventLoopThreadPool类

该类主要功能是线程池,每一条 thread 对应一个 EventLoop

线程池若不自定义线程数,则所有工作都在唯一的Loop对应线程中执行,即baseLoop_

若工作在多线程中,baseLoop_默认以轮询方式分配ChannelsubLoop

// EventLoopThreadPool.h
#pragma once
#include "noncopyable.h"

#include <functional>
#include <string>
#include <vector>
#include <memory>

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; }

    // ???谁来调用传入cb
    void start(const ThreadInitCallback &cb = ThreadInitCallback());

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

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

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

private:
    
    EventLoop *baseLoop_;
    std::string name_;
    bool started_;
    int numThreads_;
    int next_; // 轮询用的下标
    std::vector<std::unique_ptr<EventLoopThread>> threads_; // pool
    std::vector<EventLoop*> loops_;
};

// EventLoopThreadPool.cc
#include "EventLoopThreadPool.h"
#include "EventLoopThread.h"

#include <memory>

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

}
EventLoopThreadPool::~EventLoopThreadPool()
{
}

void EventLoopThreadPool::start(const ThreadInitCallback &cb)
{
    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()); // 底层创建线程,绑定一个新的EventLoop,并返回该Loop地址
    }

    // 整个服务器只有一个线程,运行baseLoop
    if(numThreads_ == 0 && cb)
    {
        cb(baseLoop_);
    }
}

// 若工作在多线程中,baseLoop_默认以轮询方式分配Channel给 subLoop
EventLoop *EventLoopThreadPool::getNextLoop()
{
    EventLoop *loop = baseLoop_;
    if(!loops_.empty())
    {
        loop = loops_[next_];
        ++next_;
        if(next_ >= loops_.size())
        {
            next_ = 0;
        }
    }

    return loop;
}

std::vector<EventLoop *> EventLoopThreadPool::getAllLoops()
{
    if(loops_.empty()) // 没有自定义线程数就只有一个mainLoop
    {
        return std::vector<EventLoop*>(1, baseLoop_);
    }
    else 
    {
        loops_;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值