【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,一经查实,立即删除!

相关文章

《深度LSTM vs 普通LSTM:训练与效果的深度剖析》

在深度学习领域&#xff0c;长短期记忆网络&#xff08;LSTM&#xff09;以其出色的处理序列数据能力而备受瞩目。而深度LSTM作为LSTM的扩展形式&#xff0c;与普通LSTM在训练和效果上存在着一些显著的不同。 训练方面 参数数量与计算量&#xff1a;普通LSTM通常只有一层或较少…

Java、Go、Rust、Node.js 的内存占比及优缺点分析

在选择编程语言进行项目开发时&#xff0c;内存占用是一个重要的考量因素。不同语言在内存管理、垃圾回收、并发模型等方面各有特点&#xff0c;影响着它们的内存使用情况。本文将对 Java、Go、Rust 和 Node.js 的内存占比进行对比&#xff0c;并分析它们的优缺点。 1. Java 的…

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;完…

《手札·行业篇》开源Odoo MES系统与SKF Observer Phoenix API在化工行业的双向对接方案

一、项目背景 化工行业生产过程复杂&#xff0c;设备运行条件恶劣&#xff0c;对设备状态监测、生产数据采集和质量控制的要求极高。通过开源Odoo MES系统与SKF Observer Phoenix API的双向对接&#xff0c;可以实现设备状态的实时监测、生产数据的自动化采集以及质量数据的同步…

redis之数据库

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

dynamic_cast和static_cast和const_cast

dynamic_cast 在 C 中的作用 dynamic_cast 是 C 运行时类型转换&#xff08;RTTI, Run-Time Type Identification&#xff09;的一部分&#xff0c;主要用于&#xff1a; 安全的多态类型转换检查类型的有效性向下转换&#xff08;Downcasting&#xff09;跨类层次的指针或引用…

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;公司需要将每个项目文件…

python lambda 关键字用法

lambda 关键字语法lambda 关键字用法1. 基本用法2. 作为 `sorted()` 的 `key` 函数3. 作为 `map()`、`filter()`、`reduce()` 的参数(1)`map()` 进行映射转换(2)`filter()` 进行条件筛选(3)`functools.reduce()` 进行累积计算4. 作为函数返回值5. 在 `if-else` 表达式中使…

数据分析对企业有什么价值

数据分析是工具&#xff0c;可以理解为一把刀&#xff0c;这把刀能够产生什么样的价值主要在于使用者。 一、基于财务的数据分析价值 基于财务数据&#xff0c;数据分析师可以进行多方面的分析&#xff0c;以下是一些常见的分析类型&#xff1a; 1. 财务报表分析 趋势分析&…

Android车机DIY开发之软件篇(十二) AOSP12下载编译

Android车机DIY开发之软件篇(十二) AOSP12下载编译 sudo apt-get update sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib gmultilib libc6-dev-i386 lib32ncurses5-dev libx11-dev lib32z-dev ccache libgl1-mesa-…

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、效果演示 四、总结 一、前言 上篇文章我介绍了如何通过云服务器或者显卡电脑来本地化…