当前位置: 首页 > news >正文

基于Linux pthread库模拟实现的线程类

基于Linux pthread库模拟实现的线程类

  • 线程类的本质
  • 对线程生命周期的控制
    • 线程创建
    • 线程属性获取
    • 线程等待
  • `int(void*)` 线程v1.0参考
  • `void(T)`线程v1.1参考

线程类的本质

无论什么语言的线程类,只要它还在当前计算机中运行,就必须调用计算机中原有的原生线程库内的接口对线程进行控制。所以所谓的封装使用的还是原生线程,但会根据实际需求例如安全、效率等对创建的线程进行控制。

这里模仿 C++11 的thread类对线程类进行描述:

  • 希望一个线程有自己的线程ID
  • 希望线程有自己的线程名
  • 用户可能希望查看当前线程的运行状态
  • 线程拥有属于自己的线程函数
  • 线程可由用户决定何时启动
  • 线程运行结束后不建议可选返回自己的返回值。因为函数有void和其他返回值类型,这使得功能实现上变得很复杂。

其他可选:

  • 一般情况下不希望线程自己进行隐式构造一个线程。
  • 线程支持移动构造,但不能支持拷贝构造。

对线程生命周期的控制

线程创建

这里我们希望线程类的对象能根据用户的需求选择是否创建

所以构造函数只会对线程的基本信息赋值,对象真正创建线程还需要调用额外的函数,这里可设置接口start。若线程启动成功则设置状态runstate为真。

线程属性获取

这里的线程类的属性有 3 种:

  1. 线程名。
  2. 线程运行状态。
  3. 线程 ID 。

分别给不同的属性设置接口即可。

线程等待

线程和进程一样,若线程已经退出,则默认返回时会被等待。

所以可通过设置等待用的接口join,通过pthread_join使得主线程等待子线程。

若线程状态变量runstate为假,则说明等待成功,join返回真。

否则join所在的线程会进行等待,修改等待结果并返回。

int(void*)线程v1.0参考

mythread.hpp:

#pragmaonce#include<functional>#include<pthread.h>#include<string>usingstd::string;// 想让线程的主体函数和main函数一样的运行模式namespacemystd{usingfunc_t=std::function<int(void*)>;template<classT>classMyThread{public:MyThread(conststring&name,func_t fc,T data=T()):_name(name),_func(fc),_data(data),_tid(pthread_t()),_runstate(false){}~MyThread(){}staticvoid*ThreadRoutine(void*args){// 通过类内方法,启动进程// 因为原生线程库无法上传包装器MyThread*ts=static_cast<MyThread*>(args);ts->_func(args);returnnullptr;}boolstart(){if(pthread_create(&_tid,nullptr,ThreadRoutine,this)==0){_runstate=true;returntrue;}returnfalse;}booljoin(){// 线程正常退出if(!_runstate)returntrue;// 主动等待线程// 可以获取返回值,现在是模型,所以不考虑设为nullptrif(pthread_join(_tid,nullptr)==0){_runstate=false;returntrue;}// 等待失败returnfalse;}// getter接口boolrunstate()const{return_runstate;}stringname()const{return_name;}pthread_ttid()const{return_tid;}private:pthread_t _tid;// 线程IDstring _name;// 线程名bool_runstate;// 线程运行状态func_t _func;// 线程本体函数T _data;// 线程类初始数据};}// namespace mystd

测试参考:

#include"mythread.hpp"// 为使用mt19937#include<chrono>#include<iostream>#include<random>#include<unistd.h>#include<vector>usingmystd::MyThread;usingstd::cout;usingstd::endl;usingstd::to_string;usingstd::vector;intf(void*args){sleep(1);MyThread<int>*mtd=static_cast<MyThread<int>*>(args);cout<<mtd->name()<<", 启动"<<endl;// 精度更高的随机数类std::mt19937_64rng(std::chrono::steady_clock().now().time_since_epoch().count());for(inti=1,x=0;i<=5;i++){x=rng()%10000+1;cout<<x<<endl;sleep(1);}return0;}voidf1(){MyThread<int>myThread("thread1",f);if(myThread.start()){cout<<"主线程:thread1运行成功, 运行状态:"<<myThread.runstate()<<endl;}else{cout<<"主线程:thread1运行失败\n";}if(myThread.join()){cout<<"主线程:等待thread1成功, 运行状态:"<<myThread.runstate()<<endl;}else{cout<<"主线程:等待thread1失败\n";}}voidf2(){vector<MyThread<int>>ts;for(inti=1;i<=5;i++){string name="Thread"+to_string(i);ts.push_back(MyThread<int>(name,f));}for(auto&x:ts){if(!x.start()){cout<<x.name()<<"启动异常\n";exit(-1);}sleep(1);}for(auto&x:ts){if(!x.join()){cout<<x.name()<<"回收异常\n";exit(-1);}cout<<x.name()<<"成功回收\n";}}intmain(){f2();return0;}

void(T)线程v1.1参考

mythread.hpp

#pragmaonce#include<functional>#include<pthread.h>#include<string>namespacemystd{usingstd::function;usingstd::string;// 因为线程函数的返回值从始至终都没有使用// 所以直接上传返回值为void的函数template<classT>usingfunc_t=function<void(T)>;// 创造一个支持选择参数类型的线程类模板template<classT>classMyThread{private:pthread_t _tid;// 线程IDstring _name;// 线程名bool_runstate;// 线程运行状态func_t<T>_func;// 线程本体函数T _data;// 计划上传给线程本体函数的参数public:explicitMyThread(conststring&name,func_t<T>fc,T data):_tid(pthread_t()),_name(name),_runstate(false),_func(fc),_data(data){}~MyThread(){}staticvoid*ThreadRoutine(void*args){// args一般情况下为线程对象MyThread*t=static_cast<MyThread*>(args);t->_func(t->_data);returnnullptr;}boolstart(){if(pthread_create(&_tid,nullptr,ThreadRoutine,this)==0){return_runstate=true;}returnfalse;}booljoin(){if(!_runstate)returntrue;if(pthread_join(_tid,nullptr)==0){_runstate=false;returntrue;}returnfalse;}// getter接口boolrunstate()const{return_runstate;}stringname()const{return_name;}pthread_ttid()const{return_tid;}};}// namespace mystd

测试程序:

#include"mythread.hpp"#include<iostream>#include<string>#include<vector>usingnamespacestd;usingnamespacemystd;structThreadData{vector<int>_arr;int*_sum;ThreadData(vector<int>arr,int*sum):_arr(arr),_sum(sum){}};voidadd(void*args){vector<int>&arr=static_cast<ThreadData*>(args)->_arr;int*sum=static_cast<ThreadData*>(args)->_sum;for(auto&x:arr)(*sum)+=x;}intmain(){vector<int>a={1,1,4,5,1,4,0,9,0,9,8,1,0};intsum=0;ThreadDatadt(a,&sum);string ThreadName="t1";MyThread<ThreadData*>t1(ThreadName,add,&dt);if(t1.start()){if(!t1.join())return-1;}cout<<sum<<endl;return0;}

但若编译器支持 C++11 ,还是建议使用thread

http://www.jsqmd.com/news/1379276/

相关文章:

  • 嵌入式系统内存碎片:成因分析与工程优化实战指南
  • 数据类设计方法论:自顶向下与自底向上实践指南
  • PoeCharm技术解析:流放之路角色构建工具的中文本地化实现方案
  • 冒险岛V176单机版电脑端安装教程
  • CMake编译器探测失败:系统性诊断与修复指南
  • GeoJSON与KML格式转换实践与深度解析
  • YOLO目标检测算法:从核心原理到工程实践全解析
  • 如何选择私有化的企业IM?部署模式、功能与安全能力分析 - BeeWorks
  • Windows Cleaner终极指南:三步彻底解决C盘空间不足,让Windows重获新生
  • C++ 模板进阶(全)
  • 从点击到接收:深入解析网络数据传输的分层模型与核心协议
  • Linux ar命令详解:静态库创建与管理实践
  • Java Timer与TimerTask深度解析:从核心机制到生产环境避坑指南
  • Linux 中定时任务:crontab
  • 妇科阴部手术图解:从可视化学习到临床实战的完整指南
  • Dhizuku终极指南:三步解锁Android设备所有者权限的完整方案
  • 护肤品牌福来有哪些产品?从一瓶身体油到四大全线护理的深度盘点 - 甄选测评馆
  • 微信机器人实战指南:30分钟构建高效智能监控系统
  • 从Function Calling到MCP:AI工具集成的协议化演进与实战
  • Windows平台Qt C++ GUI开发:从环境搭建到高效部署全攻略
  • FastAPI中GET、POST、PUT、DELETE到底怎么选?一篇讲透!
  • C++之std::map 全面详解:底层原理、最佳实践与踩坑指南
  • 小米Pad 5 Windows驱动完整指南:让你的安卓平板变身高效Windows工作站
  • 现代开发者效率工具箱:配置管理、AI助手与规则懒加载实战
  • Godot平滑插件:解决物理帧与渲染帧不同步导致的视觉卡顿
  • 4G全网通SMD贴片天线选型与PCB设计实战指南
  • B站批量取关全攻略:官方工具与脚本技术解析,实现数字断舍离
  • 护肤品牌福来有哪些产品?一文看懂德国药剂师家族的产品矩阵 - 甄选测评馆
  • 统信UOS连接Windows共享打印机:飞腾ARM平台实战指南
  • 高清磁场观察薄膜:原理、应用与实战指南