muduo网络库剖析——线程Thread类

muduo网络库剖析——线程Thread类

  • 前情
    • 从muduo到my_muduo
  • 概要
  • 框架与细节
    • 成员
    • 函数
    • 使用方法
  • 源码
  • 结尾

前情

从muduo到my_muduo

作为一个宏大的、功能健全的muduo库,考虑的肯定是众多情况是否可以高效满足;而作为学习者,我们需要抽取其中的精华进行简要实现,这要求我们足够了解muduo库。

做项目 = 模仿 + 修改,不要担心自己学了也不会写怎么办,重要的是积累,学到了这些方法,如果下次在遇到通用需求的时候你能够回想起之前的解决方法就够了。送上一段话!

在这里插入图片描述

概要

Thread类实际上是对应的one loop one thread中的thread,那么相应的thread也有自己的一些成员与函数。

框架与细节

成员

在这里插入图片描述
首先thread也有判断是否已经启动的状态位started,以及是否和父进程分离开来的状态位。以及用RAII机制来给thread进行资源管理。因为允许thread被多个对象指,所以对应的是共享指针而不是独享指针。接着是thread的线程号,这个是用来判断one loop one thread的。还有线程执行函数func_,线程的名字,有多少个线程被创建了。这个值不是单个线程独享的,所以定义为static静态变量,为了确保线程安全性,使用原子数据类型atomic_int。

在这里插入图片描述
对于atomic_int的初始化,首先肯定是在类外进行初始化的。但是这里因为atomic_int的拷贝构造函数默认是delete的,所以我们只能用构造函数的方式去初始化而不能用拷贝构造函数的方式去初始化。因此是numCreated_(0),而不是numCreated_ = 0.

函数

在这里插入图片描述
接下来是,Thread的构造函数实现。传参肯定需要线程执行函数回调,以及线程名字。并且调用设置默认名字函数。func_使用右值赋值。

在这里插入图片描述
在设置默认名字函数内,我们同时进行对线程创建数目的增加统计,如果传入的线程名字为空,就给默认的线程名字,否则就是传入的线程名。

在这里插入图片描述
接下来是线程类的析构函数,首先得先确认状态,如果是开始态,并且线程没有被分离,则线程需要分离,就调用thread自带的分离函数进行分离。

在这里插入图片描述
首先将thread启动状态位置成true。既然要启动,肯定需要让一个新线程启动起来。对与指向thread的共享智能指针,给它赋值的方式是new一个堆上的空间。因此使用shared_ptr< thread >(new thread());来创建新线程,并将指针赋给thread_。对于thread,他的创建方式这里采用c++11中的匿名函数。引用捕获变量,在匿名函数体内,我们需要记录此时的线程号。这里的好处类的作用域能够进入到新线程里,所以tid_不需要加类域。可以学习一下这种写法。除此以外,我们还要在线程中执行线程的执行回调函数。另外一个重点是,为了在start函数结束之后,tid已经是确定值,我们使用一个线程同步的方式来保证指令执行的顺序。所以我们使用了一个sem信号量。信号量的初始值是0,这样必须要等到信号量post之后才能wait到信号量。对于sem_init,第二个参数是询问是否需要用到sem给到的默认初始值,选择false就需要初始化第三个参数。

在这里插入图片描述

线程的分离也需要单独创建函数,其中将线程的状态位置1,并调用thread自带的join分离函数即可。

在这里插入图片描述
另外,定义一个CurrentThread的命名空间,其中实现了查询现在的线程的id是多少,封装在里面的是一个系统调用,大家可以学习一下。

使用方法

源码

//Thread.h
#pragma once

#include <sys/syscall.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <memory>
#include <thread>

namespace CurrentThread {
    int t_cachedTid = 0;
    inline int tid() {
        if (t_cachedTid == 0) {
            t_cachedTid = static_cast<pid_t>(::syscall(SYS_gettid));
        }
        return t_cachedTid;
    }
};

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();

    bool started_;
    bool joined_;
    std::shared_ptr<std::thread> thread_;
    pid_t tid_;
    ThreadFunc func_;
    std::string name_;
    static std::atomic_int numCreated_;
};

//Thread.cc
#include <semaphore.h>

#include "Thread.h"

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类提供的设置分离线程的方法
    }
}

// 一个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);
        // 开启一个新线程,专门执行该线程函数
        func_(); 
    }));

    // 这里必须等待获取上面新创建的线程的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;
    }
}

结尾

以上就是线程Thread类的相关介绍,以及我在进行项目重写的时候遇到的一些问题,和我自己的一些心得体会。发现写博客真的会记录好多你的成长,而且对于一个好的项目,写博客也是证明你确实有过深度思考,并且在之后面试或者工作时遇到同样的问题能够进行复盘的一种有效的手段。所以,希望uu们也可以像我一样,养成写博客的习惯,逐渐脱离菜鸡队列,向大佬前进!!!加油!!!

也希望我能够完成muduo网络库项目的深度学习与重写,并在功能上能够拓展。也希望在完成这个博客系列之后,能够引导想要学习muduo网络库源码的人,更好地探索这篇美丽繁华的土壤。致敬chenshuo大神!!!

鉴于博主只是一名平平无奇的大三学生,没什么项目经验,所以可能很多东西有所疏漏,如果有大神发现了,还劳烦您在评论区留言,我会努力尝试解决问题!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/342222.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ElasticSearch】 ElasticSearch serverless架构介绍(查询写入分离,计算存储分离)

ElasticSearch 推出了全新的serverless架构&#xff0c;将查询(search)和写入(indexing)分离&#xff0c;将计算(computing)和存储(storage)分离&#xff0c;极大提高了 ES 的可运维性&#xff0c;降低了学习成本。本文将先介绍下serverless含义&#xff0c;再介绍ElasticSearc…

ESP8266模块双模式(AP+STA)共存同时与电脑及手机进行UDP通信

1.准备工作: 硬件: ESP8266模块 USB连接线: 连接ESP8266模块到电脑 如果电脑没有USB接口,准备一个USB HUB: USB HUB 连接电脑Type-C接口,ESP8266模块连接USB HUB 软件: 安装Arduino IDE 2.2.1 在Arduino IDE中安装esp8266开发板(USB没识别芯片,要安装对应操作系统CH2340或…

LiveVideoStack人物专访:深耕多媒体二十载,他怎么看未来的视频云?

抓住已知的&#xff0c;迎面未知的。 编者按&#xff1a; 大模型、降本、出海&#xff0c;是多媒体从业者交流的高频词&#xff0c;内容与交互的需求层出不穷&#xff0c;大模型与AI的演进目不暇接&#xff0c;让增速低走的视频云迎面新的机遇和挑战。作为一个跨越中美多媒体行…

【面试深度解析】字节后端日常实习一面这么问吗?

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复…

上门回收小程序,打造回收新模式

近年来&#xff0c;我国一直秉持着环保绿色的发展理念&#xff0c;为了减少资源浪费&#xff0c;旧物回收成为了人们处理废弃物品的方式。目前&#xff0c;我国回收市场规模大约能达到3.58亿元&#xff0c;在我国经济的稳定增长和环保意识的提高下&#xff0c;回收市场规模还将…

力扣每日一题 --- 972. 相等的有理数

本题中的一个难点是怎么判断是否相等&#xff0c;如果自己写判断的话是不是很麻烦&#xff0c;判断整数之后再去判断小数部分&#xff0c;那么我们这题的另一个难点就要登场了&#xff0c;第一个难点让本题的情况变得复杂&#xff0c;第二个难点让本题变得很难想到怎么判断&…

网络安全B模块(笔记详解)- 内存取证

1.从内存文件中获取用户admin的密码并破解,将该密码作为flag值提交(密码长度为6个字符); 2.获取内存文件中系统的IP地址,将IP地址作为flag值提交; 3.获取内存文件中系统的主机名,将主机名作为flag值提交; 4.内存文件的系统中存在挖矿进程,将矿池的IP地址作为flag值提…

qml:FocusInput、TextInput 键盘输入

有2个输入框&#xff0c;默认焦点在第一个输入框&#xff0c;按Tab键可以在两个输入框之间来回切换。 FocusInput.qml import QtQuickFocusScope { //显式创建焦点范围width: 200height: 40x: 20y: 20property alias text: input.textproperty alias input: inputRectangle…

DNA序列修正*

题目 import java.util.HashMap; import java.util.Map; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();sc.nextLine();char[] sq1 sc.next().toCharArray();sc.nextLine(…

低代码(Low-Code)技术简化开发难度,快速搭建应用

目录 一、低代码技术定义 二、低代码技术优势 1.提高企业的工作效率 2.降低企业的开发成本 3.提高应用程序和业务流程的质量 三、稳定性和生产率的最佳实践 三、最后 随着数字化时代的到来&#xff0c;低代码&#xff08;Low-Code&#xff09;技术已经成为了企业数字化转…

科技、文化与旅游的融合创新:智慧文旅的未来之路

在当今社会&#xff0c;科技、文化与旅游的融合已经成为文旅产业转型升级的重要趋势。这种融合不仅有助于提升文旅产业的核心竞争力&#xff0c;更有助于推动产业的数字化转型和可持续发展。 本文将深入探讨科技、文化与旅游的融合创新&#xff0c;以及智慧文旅场景的解决方案…

使用 Swift 代码优化项目编译速度

引言 软件的性能是评价一个软件质量的重要指标&#xff0c;尤其在今天这个时代&#xff0c;性能已成为大型项目不可或缺的考虑因素之一。对于用户量极大的软件&#xff0c;如网银系统、在线购物商城等&#xff0c;更是必须保证其高效稳定的性能。在这种背景下&#xff0c;优化…

【MySQL·8.0·源码】subquery 子查询处理分析(一)

引言 在 SQL 中&#xff0c;子查询属于 Nested Query 的一种形式&#xff0c;根据 Kim 的分类[1]&#xff0c;Nested Query 即嵌套查询是一种 SQL-like 形式的查询语句嵌套在另一 SQL 中&#xff0c;SQL-like 的嵌套子句可以出现在 SELECT、FROM 和 WHERE 子句的任意位置。 在…

C++: vector

目录 1.vector的介绍 2.vector常用的接口 1.vector构造 2.迭代器iterator的使用 3.vector空间增长 4.vector的增删改查 3.vector模拟实现 如果在reverse时使用memcpy会怎么样&#xff1f; 1.vector的介绍 C中的vector是一个动态数组容器&#xff0c;可以存储任意类型的…

【算法分析与设计】二叉树的层序遍历

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xf…

Python 自动化办公:一键批量生成 PPT

Stata and Python 数据分析 一、导读 在实际工作中&#xff0c;经常需要批量处理Office文件&#xff0c;比如需要制作一个几十页的PPT进行产品介绍时&#xff0c;一页一页地制作不仅麻烦而且格式可能不统一。那么有什么办法可以一键生成PPT呢&#xff1f;Python提供的pptx 包…

Simulink|光伏并网逆变器低电压穿越仿真模型

目录 主要内容 模型研究 1.模型总览 2.boost模块 3.Inverter模块 4.控制模块 5.信号模块 结果一览 下载链接 主要内容 该模型为光伏逆变器低电压穿越仿真模型&#xff0c;采用boost加NPC拓扑结构&#xff0c;基于MATLAB/Simulink建模仿真。模型具备中点平衡…

灭火图 - 故障发现和定位的入口

通过深入分析和解决企业在可观测性和稳定性保障方面的挑战&#xff0c;Flashcat 提出了“灭火图”这一关键概念。 灭火图以服务/模块/基础组件/基础设施等为维度&#xff0c;以聚合的视角实时度量某个特定维度的可用性&#xff08;典型指标包括时延、流量、错误、饱和度&#x…

���恒峰|配网行波型故障预警定位装置:电力系统的守护神

&#xfffd;&#xfffd;&#xfffd;在电力系统中&#xff0c;设备的正常运行对于保障供电至关重要。而配网行波型故障预警定位装置就是电力系统的守护神&#xff0c;它能够实时监测设备状态&#xff0c;提前发现故障&#xff0c;确保电力供应的稳定。本文将详细介绍配网行波…

Gradle 笔记

Gradle依赖管理&#xff08;基于Kotlin DSL&#xff09; **注意&#xff1a;**如果不是工作原因或是编写安卓项目必须要用Gradle&#xff0c;建议学习Maven即可&#xff0c;Gradle的学习成本相比Maven高很多&#xff0c;而且学了有没有用还是另一回事&#xff0c;所以&#xff…