【linux学习指南】模拟线程封装与智能指针shared_ptr

请添加图片描述

文章目录

  • 📝线程封装
    • 🌉 Thread.hpp
    • 🌉 Makefile
  • 🌠线程封装第一版
    • 🌉 Makefile:
    • 🌉Main.cc
    • 🌉 Thread.hpp:
  • 🌠线程封装第二版
    • 🌉 Thread.hpp:
    • 🌉 Main.cc
  • 🌠单线程创建测试
    • 🌉 Thread.hpp
    • 🌉 main.cc
  • 🌠智能指针std::shared_ptr
  • 🚩总结


📝线程封装

🌉 Thread.hpp

// Thread.hpp
#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <pthread.h>
namespace ThreadModule
{// 原⼦计数器,⽅便形成线程名称std::uint32_t cnt = 0;// 线程要执⾏的外部⽅法,我们不考虑传参,后续有std::bind 来进⾏类间耦合using threadfunc_t = std::function<void()>;// 线程状态enum class TSTATUS{THREAD_NEW,THREAD_RUNNING,THREAD_STOP};// 线程class Thread{private:static void *run(void *obj){Thread *self = static_cast<Thread *>(obj);pthread_setname_np(pthread_self(), self->_name.c_str()); // 设置线程名称self->_status = TSTATUS::THREAD_RUNNING;if (!self->_joined){pthread_detach(pthread_self());}self->_func();return nullptr;}void SetName(){// 后期加锁保护_name = "Thread-" + std::to_string(cnt++);}public:Thread(threadfunc_t func) : _status(TSTATUS::THREAD_NEW),_joined(true), _func(func){SetName();}void EnableDetach(){if (_status == TSTATUS::THREAD_NEW)_joined = false;}void EnableJoined(){if (_status == TSTATUS::THREAD_NEW)_joined = true;}bool Start(){if (_status == TSTATUS::THREAD_RUNNING)return true;int n = ::pthread_create(&_id, nullptr, run, this);if (n != 0)return false;return true;}bool Join(){if (_joined){int n = pthread_join(_id, nullptr);if (n != 0)return false;return true;}return false;}~Thread() {}private:std::string _name;pthread_t _id;TSTATUS _status;bool _joined;threadfunc_t _func;};
}

🌉 Makefile

// main.cc
#include <iostream>
#include <unistd.h>
#include "Thread.hpp"
void hello1()
{char buffer[64];pthread_getname_np(pthread_self(), buffer, sizeof(buffer) - 1);while (true){}std::cout << "hello world, " << buffer << std::endl;sleep(1);
}
void hello2()
{char buffer[64];pthread_getname_np(pthread_self(), buffer, sizeof(buffer) - 1);while (true){std::cout << "hello world, " << buffer << std::endl;sleep(1);}
}
int main()
{pthread_setname_np(pthread_self(), "main");ThreadModule::Thread t1(hello1);t1.Start();ThreadModule::Thread t2(std::bind(&hello2));t2.Start();t1.Join();t2.Join();return 0;
}

运⾏结果查询

$ ps -aLPID  LWP  TTY       TIME    CMD       
195828  195828 pts/1   00:00:00 main
195828  195829 pts/1   00:00:00 Thread-0  
195828  195830 pts/1   00:00:00 Thread-1 

🌠线程封装第一版

🌉 Makefile:

bin=testThread
cc=g++
src=$(wildcard *.cc)
obj=$(src:.cc=.o)$(bin):$(obj)$(cc) -o $@ $^ -lpthread
%.o:%.cc$(cc) -c $< -std=c++17.PHONY:test
test:echo $(src)echo $(obj)

🌉Main.cc

#include "Thread.hpp"
#include <unordered_map>
#include <memory>// using thread_ptr_t = std::shared_ptr<ThreadModule::Thread>;#define NUM 10;class threadData
{
public:int max;int start;
};void Count(threadData td)
{for(int i = td.start; i < td.max; i++){std::cout<< "i == " <<i <<std::endl;sleep(1);}
}int main()
{threadData td;td.max = 60;td.start = 50;//使用lamda表达式封装Count成一个不接受参数的可调用对象auto func = [td](){Count(td);};ThreadModule::Thread<threadData> t(func);t.Start();t.Join();return 0;
}

🌉 Thread.hpp:

//V1
namespace ThreadModule
{// template<typename T>using func_t = std::function<void()>;static int number = 1;enum class TSTATUS{NEW,RUNNING,STOP};template<typename T>class Thread{private:static void* Routine(void *args){Thread* t = static_cast<Thread *>(args);t->_status = TSTATUS::RUNNING;t->_func();return nullptr;}void EnableDetach(){_joinable = false;}public:Thread(func_t func): _func(func), _status(TSTATUS::NEW), _joinable(true){_name = "Thread - " + std::to_string(number++);_pid = getpid();}bool Start(){if (_status != TSTATUS::RUNNING){int n = ::pthread_create(&_tid, nullptr, Routine, this); // 这里使用thisif (n != 0)return false;return true;}return true;}bool Stop(){if (_status != TSTATUS::RUNNING){int n = ::pthread_cancel(_tid);if (n != 0)return false;_status = TSTATUS::STOP;                return true;}return false;}bool Join(){if(_joinable){int n = ::pthread_join(_tid, nullptr);if(n != 0)return false;_status = TSTATUS::STOP;                return true;     }return false;}void Detach(){EnableDetach();pthread_detach(_tid);}bool IsJoinable(){return _joinable;}std::string Name(){return _name;}~Thread(){}private:std::string _name;pthread_t _tid;pid_t _pid;bool _joinable; // 是否是分离的, 默认不是func_t _func;TSTATUS _status;};
}#endif

在这里插入图片描述
加粗样式

🌠线程封装第二版

🌉 Thread.hpp:

#ifndef THREAD_HPP
#define THREAD_HPP#include <iostream>
#include <string>
#include <pthread.h>
#include <functional>
#include <sys/types.h>
#include <unistd.h>//V2
namespace ThreadModule
{static int number = 1;enum class TSTATUS{NEW,RUNNING,STOP};template<typename T>class Thread{using func_t = std::function<void(T)>;private://成员方法static void *Routine(void* args){Thread<T> *t = static_cast<Thread<T>*>(args);t->_status = TSTATUS::RUNNING;t->_func(t->_data);return nullptr;}void EnableDetach(){_joinable = false;}public:Thread(func_t func, T data):_func(func),_data(data),_status(TSTATUS::NEW),_joinable(true){_name = "Thread -" +std::to_string(number++);_pid = getpid();}bool Start(){if(_status != TSTATUS::RUNNING){int n = pthread_create(&_tid, nullptr, Routine, this);if(n != 0)return false;return true;}return false;}bool Stop(){if(_status == TSTATUS::RUNNING){int n = ::pthread_cancel(_tid);if(n != 0)return false;_status = TSTATUS::STOP;return true;}return false;}bool Join(){if(_joinable){int n = ::pthread_join(_tid, nullptr);if(n != 0)return false;_status = TSTATUS::STOP;return true;}return false;}bool IsJoinale(){return _joinable;}std::string Name(){return _name;}~Thread(){}private:std::string _name;pthread_t _tid;bool _joinable;//是否是分离的,默认不是func_t _func;pid_t _pid;TSTATUS _status;T _data;};
}#endif

🌉 Main.cc

#include "Thread.hpp"
#include <unordered_map>
#include <memory>using thread_ptr_t = std::shared_ptr<ThreadModule::Thread<int>>;#define NUM 10class threadData
{
public:int max;int start;
};void Count(threadData td)
{for(int i = td.start; i < td.max; i++){std::cout<< "i == " <<i <<std::endl;sleep(1);}
}
int main()
{//先描述再组织std::unordered_map<std::string, thread_ptr_t> threads;//如果我们要创建多线程呢?for(int i = 0; i< NUM ; i++){auto func = [](){while(true){std::cout<< "hello world" << std::endl;sleep(1);}};int threadData = i+1; thread_ptr_t t= std::make_shared<ThreadModule::Thread<int>>([func](int){func();}, threadData);std::cout<< "Create thread with name : "<<t->Name() <<std::endl;threads[t->Name()] = t;}for(auto &thread : threads){thread.second->Start();}for(auto &thread : threads){thread.second->Join();}

在这里插入图片描述
在这里插入图片描述

🌠单线程创建测试

🌉 Thread.hpp

#ifndef THREAD_HPP
#define THREAD_HPP#include <iostream>
#include <string>
#include <pthread.h>
#include <functional>
#include <sys/types.h>
#include <unistd.h>//V2
namespace ThreadModule
{static int number = 1;enum class TSTATUS{NEW,RUNNING,STOP};template<typename T>class Thread{using func_t = std::function<void(T)>;private://成员方法static void *Routine(void* args){Thread<T> *t = static_cast<Thread<T>*>(args);t->_status = TSTATUS::RUNNING;t->_func(t->_data);return nullptr;}void EnableDetach(){_joinable = false;}public:Thread(func_t func, T data):_func(func),_data(data),_status(TSTATUS::NEW),_joinable(true){_name = "Thread -" +std::to_string(number++);_pid = getpid();}bool Start(){if(_status != TSTATUS::RUNNING){int n = pthread_create(&_tid, nullptr, Routine, this);if(n != 0)return false;return true;}return false;}bool Stop(){if(_status == TSTATUS::RUNNING){int n = ::pthread_cancel(_tid);if(n != 0)return false;_status = TSTATUS::STOP;return true;}return false;}bool Join(){if(_joinable){int n = ::pthread_join(_tid, nullptr);if(n != 0)return false;_status = TSTATUS::STOP;return true;}return false;}bool IsJoinale(){return _joinable;}std::string Name(){return _name;}~Thread(){}private:std::string _name;pthread_t _tid;bool _joinable;//是否是分离的,默认不是func_t _func;pid_t _pid;TSTATUS _status;T _data;};
}

🌉 main.cc

#include "Thread.hpp"
#include <unordered_map>
#include <memory>using thread_ptr_t = std::shared_ptr<ThreadModule::Thread<int>>;#define NUM 10class threadData
{
public:int max;int start;
};void Count(threadData td)
{for(int i = td.start; i < td.max; i++){std::cout<< "i == " <<i <<std::endl;sleep(1);}
}int main()
{auto func = [](){while(true){std::cout<< "hello world" <<std::endl;sleep(1);}};std::function<void(int)> wrappedFunc2 = [func](int){ func(); };int signalTreadData = 5;ThreadModule::Thread<int> t( wrappedFunc2,signalTreadData);// std::cout<< "Create thread with name : "<<t->Name() <<std::endl;// t.Start();// t.Join();t.Start();std::cout<< t.Name() << " is running" <<std::endl;std::cout<<std::flush;//手动刷新缓冲期sleep(5);if (t.Stop()) {std::cout << "Stop thread : " << t.Name() << std::endl;std::cout << std::flush; // 手动刷新缓冲区} else {std::cout << "Failed to stop thread : " << t.Name() << std::endl;std::cout << std::flush; // 手动刷新缓冲区}sleep(1);if (t.Join()) {std::cout << "Join thread : " << t.Name() << std::endl;std::cout << std::flush; // 手动刷新缓冲区} else {std::cout << "Failed to join thread : " << t.Name() << std::endl;std::cout << std::flush; // 手动刷新缓冲区}return 0;
}

在这里插入图片描述
在这里插入图片描述

🌠智能指针std::shared_ptr

std::shared_ptr 是 C++ 标准库 <memory> 头文件中提供的一种智能指针,用于管理动态分配的对象,它实现了共享所有权的语义,下面为你详细介绍它的作用、工作原理以及在你给出的代码中的使用场景。

作用

在传统的 C++ 中,使用 new 操作符动态分配内存后,需要手动使用 delete 操作符释放内存,否则会导致内存泄漏。std::shared_ptr 可以自动管理动态分配的对象的生命周期,当没有任何 std::shared_ptr 指向该对象时,它会自动释放对象所占用的内存,从而避免了手动管理内存带来的复杂性和潜在的内存泄漏问题。

工作原理

std::shared_ptr 使用引用计数的机制来管理对象的生命周期。每个 std::shared_ptr 都维护一个引用计数,记录有多少个 std::shared_ptr 共享同一个对象。当一个新的 std::shared_ptr 指向一个对象时,引用计数加 1;当一个 std::shared_ptr 被销毁或者指向其他对象时,引用计数减 1。当引用计数变为 0 时,说明没有任何 std::shared_ptr 再指向该对象,此时 std::shared_ptr 会自动调用对象的析构函数并释放内存。

  1. using thread_ptr_t = std::shared_ptr<ThreadModule::Thread<int>>;
    这行代码使用 using 关键字定义了一个类型别名 thread_ptr_t,它实际上是 std::shared_ptr<ThreadModule::Thread<int>> 的别名。这样做的好处是可以简化代码,避免在后续使用时多次书写冗长的类型名。这里的 ThreadModule::Thread<int> 是一个模板类的实例化,表示一个线程对象,std::shared_ptr 用于管理这个线程对象的生命周期。

  2. std::unordered_map<std::string, thread_ptr_t> threads;
    这行代码定义了一个 std::unordered_map,它是一个无序关联容器,用于存储键值对。键的类型是 std::string,值的类型是 thread_ptr_t,也就是 std::shared_ptr<ThreadModule::Thread<int>>。通过这种方式,可以将线程对象与一个字符串键关联起来,方便对线程对象进行管理和查找。

  3. thread_ptr_t t = std::make_shared<ThreadModule::Thread<int>>( ... );
    这行代码使用 std::make_shared 函数创建了一个 std::shared_ptr<ThreadModule::Thread<int>> 对象,并将其赋值给 tstd::make_shared 是一个便捷的函数,用于创建 std::shared_ptr 对象,它会在一次内存分配中同时分配对象和引用计数所需的内存,比分别使用 newstd::shared_ptr 的构造函数更加高效。括号内的参数是传递给 ThreadModule::Thread<int> 构造函数的参数,用于初始化线程对象。

示例代码

#include <iostream>
#include <memory>class MyClass {
public:MyClass() { std::cout << "MyClass constructor" << std::endl; }~MyClass() { std::cout << "MyClass destructor" << std::endl; }void doSomething() { std::cout << "Doing something..." << std::endl; }
};int main() {// 创建一个 std::shared_ptr 对象std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();// 复制一个 std::shared_ptr 对象,引用计数加 1std::shared_ptr<MyClass> ptr2 = ptr1;// 调用对象的成员函数ptr1->doSomething();// 当 ptr1 和 ptr2 离开作用域时,引用计数减 1// 当引用计数变为 0 时,对象会被自动销毁return 0;
}

代码解释

  • main 函数中,首先使用 std::make_shared 创建了一个 std::shared_ptr<MyClass> 对象 ptr1,此时引用计数为 1。
  • 然后将 ptr1 赋值给 ptr2,引用计数变为 2。
  • 调用 ptr1->doSomething() 来调用对象的成员函数。
  • ptr1ptr2 离开 main 函数的作用域时,它们会被销毁,引用计数减 1。当引用计数变为 0 时,MyClass 对象的析构函数会被自动调用,释放对象所占用的内存。

🚩总结

如果要像C++11那样进⾏可变参数的传递,是可以这样设计的,但是太⿇烦了,真到了哪⼀步,就直接⽤c++11吧,我们的⽬标主要是理解系统概念对象化,此处不做复杂设计,⽽且后续可以使⽤std::bind来进⾏对象间调⽤

请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s的安装

1. k8s的安装 192.168.48.6 master01 192.168.481.6 node01 192.168.48.26 node02 三台机器一起操作 1.swapoff -a &#xff1a;关闭交换分区 2. iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X 3. cat > /etc/sy…

字节跳动大模型应用 Go 开发框架 —— Eino 实践

前言 开发基于大模型的软件应用&#xff0c;就像指挥一支足球队&#xff1a;组件是能力各异的队员&#xff0c;编排是灵活多变的战术&#xff0c;数据是流转的足球。Eino 是字节跳动开源的大模型应用开发框架&#xff0c;拥有稳定的内核&#xff0c;灵活的扩展性&#xff0c;完…

redis之数据库

文章目录 服务器中的数据库切换数据库数据库键空间读写键空间时的维护操作 设置键的生存时间或过期时间保存过期时间过期键的判定过期键删除策略清性删除策略的实现定期删除策略的实现 总结 服务器中的数据库 Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结…

Qt文本高亮显示【QSyntaxHighlighter】功能代码讲解

QSyntaxHighlighter 是 Qt 框架中的一个重要类&#xff0c;专门用于为文本内容提供语法高亮功能。它广泛应用于文本编辑器、代码编辑器、日志查看器等应用程序中&#xff0c;允许开发者对文本中的不同部分应用不同的格式&#xff0c;如字体颜色、背景色、加粗等。通过这个类&am…

MS08067练武场--WP

免责声明&#xff1a;本文仅用于学习和研究目的&#xff0c;不鼓励或支持任何非法活动。所有技术内容仅供个人技术提升使用&#xff0c;未经授权不得用于攻击、侵犯或破坏他人系统。我们不对因使用本文内容而引起的任何法律责任或损失承担责任。 注&#xff1a;此文章为快速通关…

WPF正则表达式验证输入是否包含中文字母数字,不能是纯符号

1、验证纯中文 string pattern "[\u4e00-\u9fa5]"; // 创建Regex对象 Regex regex new Regex(pattern); // 判断输入字符串是否包含中文 if (!regex.IsMatch(name)) { //resultTextBlock.Text …

【Matlab优化算法-第13期】基于多目标优化算法的水库流量调度

一、前言 水库流量优化是水资源管理中的一个重要环节&#xff0c;通过合理调度水库流量&#xff0c;可以有效平衡防洪、发电和水资源利用等多方面的需求。本文将介绍一个水库流量优化模型&#xff0c;包括其约束条件、目标函数以及应用场景。 二、模型概述 水库流量优化模型…

《qt open3d中添加随机点采样》

qt open3d中添加随机点采样 效果展示二、流程三、代码效果展示 二、流程 创建动作,链接到槽函数,并把动作放置菜单栏 参照前文 三、代码 1、槽函数实现 void on_actionFilterRandomDownSample_triggered();void MainWindow::on_act

【图片转换PDF】多个文件夹里图片逐个批量转换成多个pdf软件,子文件夹单独合并转换,子文件夹单独批量转换,基于Py的解决方案

建筑设计公司在项目执行过程中&#xff0c;会产生大量的设计图纸、效果图、实景照片等图片资料。这些资料按照项目名称、阶段、专业等维度存放在多个文件夹和子文件夹中。 操作需求&#xff1a;为了方便内部管理和向客户交付完整的设计方案&#xff0c;公司需要将每个项目文件…

Windows 安装 DeepSeek 教程和open webui 图形化部署(非docker)

Windows 安装 Ollama : 步骤 1&#xff1a;下载并安装 Ollama 官网&#xff1a;奥拉马 点击下载 选择windows版本。 双击安装包 点击【Install】&#xff08;注意&#xff1a;安装包是直接安装在C盘的&#xff0c;并不支持更改路径&#xff0c;因此C盘的空间必须要至少大于5…

每日学习 设计模式 五种不同的单例模式

狮子大佬原文 https://blog.csdn.net/weixin_40461281/article/details/135050977 第一种 饿汉式 为什么叫饿汉,指的是"饿" 也就是说对象实例在程序启动时就已经被创建好,不管你是否需要,它都会在类加载时立即实例化,也就是说 实例化是在类加载时候完成的,早早的吃…

OpenCV 相机标定流程指南

OpenCV 相机标定流程指南 前置准备标定流程结果输出与验证建议源代码 OpenCV 相机标定流程指南 https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html https://learnopencv.com/camera-calibration-using-opencv/ 前置准备 制作标定板&#xff1a;生成高精度棋…

没有服务器和显卡电脑如何本地化使用deepseek|如何通过API使用满血版deepseek

目录 一、前言二、使用siliconflow硅基流动 API密钥1、注册硅基流动2、创建API密钥3、下载AI客户端4、使用API密钥5、效果演示 三、使用deepseek官方API密钥1、创建API密钥2、使用API密钥3、效果演示 四、总结 一、前言 上篇文章我介绍了如何通过云服务器或者显卡电脑来本地化…

python+unity落地方案实现AI 换脸融合

先上效果再说技术结论&#xff0c;使用的是自行搭建的AI人脸融合库&#xff0c;可以离线不受限制无限次生成&#xff0c;有需要的可以后台私信python ai换脸融合。 TODO 未来的方向&#xff1a;3D人脸融合和AI数据训练 这个技术使用的是openvcinsighface&#xff0c;openvc…

windows + visual studio 2019 使用cmake 编译构建静、动态库并调用详解

环境 windows visual studio 2019 visual studio 2019创建cmake工程 1. 静态库.lib 1.1 静态库编译生成 以下是我创建的cmake工程文件结构&#xff0c;只关注高亮文件夹部分 libout 存放编译生成的.lib文件libsrc 存放编译用的源代码和头文件CMakeLists.txt 此次编译CMak…

【前端】几种常见的跨域解决方案代理的概念

几种常见的跨域解决方案&代理的概念 一、常见的跨域解决方案1. 服务端配置CORS&#xff08;Cross-Origin Resource Sharing&#xff09;&#xff1a;2. Nginx代理3. Vue CLI配置代理&#xff1a;4 .uni-app在manifest.json中配置代理来解决&#xff1a;5. 使用WebSocket通讯…

Git 分布式版本控制工具使用教程

1.关于Git 1.1 什么是Git Git是一款免费、开源的分布式版本控制工具&#xff0c;由Linux创始人Linus Torvalds于2005年开发。它被设计用来处理从很小到非常大的项目&#xff0c;速度和效率都非常高。Git允许多个开发者几乎同时处理同一个项目而不会互相干扰&#xff0c;并且在…

基于java手机销售网站设计和实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

GitHub Pages + Jekyll 博客搭建指南(静态网站搭建)

目录 &#x1f680; 静态网站及其生成工具指南&#x1f30d; 什么是静态网站&#xff1f;&#x1f4cc; 静态网站的优势⚖️ 静态网站 VS 动态网站 &#x1f680; 常见的静态网站生成器对比&#x1f6e0;️ 使用 GitHub Pages Jekyll 搭建个人博客&#x1f4cc; 1. 创建 GitHu…

1.【线性代数】——方程组的几何解释

一 方程组的几何解释 概述举例举例一1. matrix2.row picture3.column picture 概述 三种表示方法 matrixrow picturecolumn picture 举例 举例一 { 2 x − y 0 − x 2 y 3 \begin{cases} 2x - y 0 \\ -x 2y 3 \end{cases} {2x−y0−x2y3​ 1. matrix [ 2 − 1 − 1 …