Muduo网络库解析 ---线程模块

前言

重写Muduo库实现核心模块的Git仓库

注:本文将重点剖析 Muduo 网络库的核心框架,深入探讨作者精妙的代码设计思路,并针对核心代码部分进行重写,将原本依赖 boost 的实现替换为原生的 C++11 语法。需要说明的是,本文并不打算对整个 Muduo 库进行完整的重写。Muduo库源码链接

在前面几篇博客中,我们已经对 基础模块事件循环模块 进行了初步讲解,特别是在事件循环模块中重点介绍了 ChannelPoller 以及 EventLoop 的作用,分析了它们之间的联系以及协同工作的方式。

在此基础上,我们可以进一步思考一个问题:如何保证 EventLoop 在一个线程中独立运行,即如何确保线程对 EventLoop 生命周期的控制? 用户在使用 Muduo 库时,可以通过 setThreadNum 方法来设置 SubLoop(工作线程) 的数量,从而创建多个 EventLoop。这就引出了一个关键点:如何实现并严格保证 One Loop Per Thread 的设计原则?

答案是:我们将 线程 抽象为 Thread 类,并进一步结合 EventLoopThread,设计出 EventLoopThread 类。在此基础上,为了实现多个工作线程的管理,引入了线程池的概念,将多个 EventLoopThread 抽象为 EventLoopThreadPool。通过 EventLoopThreadPool,用户只需设置线程数量,即可创建多个事件循环,同时严格遵循了 One Loop Per Thread 的设计原则。

本篇将介绍Muduo网络库的线程有关模块,具体如下:

  • Thread
  • EventThread
  • EventThreadPool

Thread

CurrentThread

在上篇博客中提到:在EventLoop类中有一个成员变量(threadId_ :const pid_t),其用来标识此EventLoop的线程号。在构造函数中,对其初始化如下:

threadId_(CurrentThread::tid())

CurrentThread::tid(), 现在我们来拨开它神秘的面纱。其定义如下(不是源版,而是精简重写版):

/*
	CurrentThread.h
*/
namespace CurrentThread
{
   
    /*
        每个线程都有一个唯一的ID
    */
    extern thread_local int t_cachedTid;

    void cacheTid();

    inline int tid()
    {
   
        if(__builtin_expect(t_cachedTid == 0, 0)){
   
            cacheTid();
        }
        return t_cachedTid;
    }
}

/*
	CurrentThread.cc
*/
namespace CurrentThread
{
   
    thread_local int t_cachedTid = 0;

    void cacheTid()
    {
   
        if(t_cachedTid == 0)
        {
   
            t_cachedTid = static_cast<pid_t>(::syscall(SYS_gettid));
        }
    }
}

解析

  • t_cachedTid
    这是一个整型类型,并用thread_local修饰。这意味着每个线程都有一个单独的t_cachedTid,其含义表示为每个线程的tid为CurrentThread::t_cachedTid。每个线程都可以通过CurrentThread::tid()返回它们自己的线程号(因为tid()返回t_cachedTid)。

  • cacheTid
    此函数的作用为获取本线程的线程号并将其缓存起来。获取TID所用的系统调用为syscall(SYS_gettid),而pthread_self()获取的也是线程ID。它们两个有什么区别呢?

    syscall(SYS_gettid)返回的是当前线程的内核线程 ID(Thread ID,简称 TID)。
    pthread_self 获取的是线程库(POSIX Thread Library)中的线程 ID,简称为 pthread_t
    TID是由 Linux 内核分配的,线程在内核中的唯一标识,系统中只有一个TID

    pthread_t是由用户态的线程库管理的,并不是内核线程的唯一标识。

  • tid()
    其作用为返回当前的线程TID。其中用到了__builtin_expect(t_cachedTid == 0, 0),表示t_cachedTid == 0这个表达式为假的概率更高。

    __builtin_expect 是 GCC 提供的一种编译器内置函数,用于优化分支预测。它的作用是让程序员显式地告诉编译器某个条件的可能性,从而帮助编译器生成更高效的代码。
    第一个参数为一个条件表达式,第二个参数表示为 表达式哪个(真/假)概率较高。

Thread代码

Thread 类的作用可以概括为:在一个线程中运行指定的函数,同时提供控制该线程(启动、停止等)的接口Muduo作者对线程进行了封装,在这里我们进行简化利用C++11中的thread库表示。

Muduo网络库解析 ---线程模块_第1张图片

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 {
    

你可能感兴趣的:(剖析Muduo,网络,c++,tcp/ip)