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

深入了解linux系统—— 线程封装

C++11线程库

C++11也提供了对应的线程库,在头文件<thread>中;C++11将其封装成thread类,通过类实例化出对象,调用类内成员方法进行线程控制。

#include <iostream>
#include <thread>
#include <unistd.h>
using namespace std;
void func()
{int cnt = 3;while(cnt--){cout<<"thread : "<<cnt<<endl;sleep(1); }
}
int main()
{thread td(func);//创建线程sleep(5);td.detach();//线程分离td.join();//线程等待return 0;
}

线程封装

C++11实现的线程thread是对pthread库的封装,这里也对pthread库做简单封装;

首先要封装实现一个thread类,其中要包括成员变量:线程ID、分离状态(detach)、运行状态(runing)、返回值、线程名称等等

namespace mypthread
{class thread{public:private:pthread_t _tid;std::string _name;bool _detach;bool _runing;void* retval;};
}

构造函数(创建线程)

C++thread一样,在创建对象时就将线程要执行的方法传入,那在thread类中,就要存在一个成员变量func(没有参数、没有返回值的)

这里就要使用C++11语法:function包装器

using func = std::function<void(void)>;这样在类内定义void(void)类型的成员变量。

但是,我们知道,在调用pthread_create创建线程时,要传递的函数类型是(void*(void*))类型的,所以就还要存在一个void*(void*)类型的函数;我们可以将该方法实现成静态成员函数

但是,这个函数还要可以访问thread类内成员func,静态成员函数没有隐藏的this指针,这里可以将this作为参数传递给线程要调用的方法(pthread_create第四个参数)

namespace mypthread
{static int count = 1;using func = std::function<void(void)>;class thread{static void *routine(void *msg){// 传递的是this指针thread *td = static_cast<thread *>(msg);std::cout << td->_name << std::endl;// 调用funtd->_fun();return (void *)100;}public:thread(func fun) : retval(nullptr), _fun(fun), _detach(false){_name = "thread-" + std::to_string(count);count++;int n = pthread_create(&_tid, nullptr, routine, (void *)this);if (n != 0){std::cerr << "pthread_create" << std::endl;}_runing = true;}private:pthread_t _tid;std::string _name;bool _detach;bool _runing;void *retval;func _fun;};
}

这里为了方便测试,存在一个count计数器,为了生成线程名称_name

线程分离

在创建线程之后,我们可以设置线程分离;

        void Detach(){if(_detach)return;pthread_detach(_tid);_deatch = true;}

线程取消

我们可以调用pthread_cancel来取消线程;

        bool Cancel(){if (_runing == false)return;int n = pthread_cancel(_tid);if (n != 0){std::cerr << "pthread_cancel" << std :: endl;return false;}return true;}

线程等待

新创建的线程在运行结束后,需要进行线程等待;这里实现就直接调用pthread_join阻塞等待线程;然后将线程的返回值放到_retval中。

      void Join(){pthread_join(_tid, &_retval);}

析构函数(回收线程)

pthread库进行面向对象封装,在thread析构函数中,就要调用线程取消Cancel,然后调用Join回收线程并获取线程的返回值。

        ~thread(){Cancel();Join();}

测试thread

using namespace mypthread;
void test()
{int cnt = 3;while (cnt--){std::cout << "new thread : " << cnt << std::endl;sleep(1);}
}
int main()
{thread td(test);sleep(5);return 0;
}

在这里插入图片描述

这样在main函数中,就算我们没有显示调用Join等待,在线程thread对象出了作用域后,自动调用析构函数从而调用CancelJoin回收线程。

番外

对于线程封装,这里实现了另外一种版本:

在创建thread对象之后并不会立即创建新线程,而是调用Start才会创建新线程;

此外我们可以在没有创建线程时设置detach分离状态,也可以在线程运行时设置detach分离状态;

namespace mythread
{static int count = 1;using func_t = std::function<void()>;class Thread{static void *rontinue(void *args){Thread *pt = static_cast<Thread *>(args);pt->_fun();return (void*)pt->_name.c_str();}void EnableDetach() { _detach = true; }void EnableRuning() { _runing = true; }public:Thread(func_t fun) : _tid(-1), _detach(false), _runing(false), _fun(fun), _retval(nullptr){_name = "thread- " + std::to_string(count);count++;}void Start(){if (_runing)return;// 创建线程int n = pthread_create(&_tid, nullptr, rontinue, this);if (n != 0){std::cerr << "pthread_create" << std::endl;exit(1);}EnableRuning();Detach();}void Detach(){if (_detach){if (_runing){pthread_detach(_tid);}EnableDetach();}}void Cancel(){if (_runing){pthread_cancel(_tid);}_runing = false;}void Join(){if (_detach)return;pthread_join(_tid, &_retval);}std::string GetName(){return _name;}private:pthread_t _tid;    // 线程idstd::string _name; // 线程名bool _detach;      // 分离状态bool _runing;      // 运行状态func_t _fun;         // 线程执行函数void *_retval;     // 返回值};
}

简单总结:

本篇文章对pthread库做了简单封装,实现了简单的thread类。

http://www.xdnf.cn/news/18929.html

相关文章:

  • 【prism】Prism 弹窗在 ViewModel 中控制大小的实践总结
  • 视觉工具:文字显示、图像标注与多模板匹配
  • 「大模型学习」(15)Prompt Tuning → P-Tuning v1 → P-Tuning v2
  • STM32G4 SVPWM VF开环强拖电机
  • 两周年创作纪念,忆笑傲江湖岁月
  • 【生产实践】局域网多服务器多用户SSH登录批量测试(附完整shell脚本)
  • Linux-服务器初始化
  • 【智能化解决方案】大模型智能推荐选型系统方案设计
  • week5-[字符数组]查找
  • GD32VW553-IOT开发板测评 搭建环境到电灯(QA分享)
  • Element中table组件(el-table)右侧滚动条空白占位gutter处理
  • vue3和react的异同点
  • Tesseract OCR之基线拟合和单词检测
  • 从0开始学习Java+AI知识点总结-26.web实战(Springboot原理)
  • Linux服务器安全配置与NTP时间同步
  • 【Python系列】Flask 和 FastAPI对比
  • 【深度学习新浪潮】SAM 2实战:Meta新一代视频分割模型的实时应用与Python实现
  • Boris FX Samplitude Suite 2025.0.0 音频录制/编辑和母带处理
  • springcloud篇5-微服务保护(Sentinel)
  • 数字IC前端设计——前仿篇(VCS,DVE,Verdi)
  • 企业级集群部署gpmall商城:MyCat+ZooKeeper+Kafka 环境部署与商城应用上线流程
  • Linux SSH 基于密钥交换的自动登录原理简介及配置说明
  • 税务岗位职场能力解析与提升路径规划
  • spring全家桶
  • VMware 中 Ubuntu 右上角网络图标消失的 5 种终极修复方案
  • Android 中使用开源库 ZXing 生成二维码图片
  • Android 播放MP4格式,大视频 几个小时的视频点击快进键视频进度会倒退一秒
  • 基于 Elasticsearch 解决分库分表查询难题
  • MySQL 索引:结构、对比与操作实践指南
  • OpenAI o1:OpenAI最新推出的AI大语言模型,更擅长推理也更贵