Linux多线程——利用C++模板对pthread线程库封装
文章目录
- 线程封装
- 主要框架
- 线程启动
- 线程等待
- 其他信息
- 测试函数
线程封装
我们之前介绍过pthread的线程库,这个线程库主要是基于C语言的void*指针来进行传参和返回
我们使用C++的模板对其封装可以让他的使用更加方便,并且经过测试可以让我们更加直观的了解到线程互斥和同步的重要性
主要框架
要对线程库进行封装,但是首先这个线程库的基本功能肯定要有
void*使用模板解决,函数指针使用包装器解决
那么基本框架就能搭建出来了
#pragma once#include<iostream>
#include<string>
#include<functional>
#include<pthread.h>template<class T>
using Func_t = std::function<void(T)>; // 参数类型为T 返回值为空的函数template<class T>
class Thread{
public:Thread(const std::string& tname, Func_t<T> func, T data): _Tid(0), _ThreadName(tname), _IsRunning(false), _Func(func), _Data(data){}~Thread(){}bool Start() // 线程启动{}bool Join() // 线程等待{}private:pthread_t _Tid; // 线程id 也可以用LWP来表示,主要是为了区分不同线程std::string _ThreadName; // 线程名称bool _IsRunning; // 区分线程运行状态Func_t<T> _Func; // 回调函数T _Data;
};
线程启动
因为这个类创建之后并没有真正创建线程,没有分配线程id,而Start作为主线程需要完成的任务就是创建新线程,更改线程的运行状态,返回线程创建成功与否
bool Start()
{bool Start() // 线程启动{int n = pthread_create(&_Tid, nullptr, ThreadRoutine, this);if(n==0){_IsRunning = true;return true;}else return false;}
}
这里需要注意的点是,传入的参数直接就是this指针,相当于把整个对象传进去了
这是为什么呢
首先ThreadRoutine是需要设置在类内设置的,为了安全性考虑
那么他如果作为类内的成员函数,他的参数就是this指针和一个void*的指针
这样明显是不符合pthread_create对这个函数的要求,一个解决办法就是将其设置为静态成员函数,另一个办法就是设置在类外了
这样一来,作为静态成员函数是无法直接使用类内成员的,也就是无法使用这个回调函数,因此将this指针作为参数传递进去是一个很好的选择
static void* ThreadRoutine(void* args){Thread* tp = static_cast<Thread*>(args);tp->_Func(tp->_Data); // 调用回调函数return nullptr;}
线程等待
bool Join(){if (!_IsRunning) // 如果新线程已经结束运行了,那就没有等待的必要了return true;int n = pthread_join(_Tid, nullptr);if (n == 0){_IsRunning = false;return true;}return false;}
等待的代码就比较简单了
其他信息
std::string GetThreadName(){return _ThreadName;}bool IsRunning(){return _IsRunning;}
这样我们就封装了一个最简单的线程库
测试函数
我们假设自己写了一个抢票逻辑,采用多线程的方法对其进行调用
#include <iostream>
#include <unistd.h>
#include <vector>
#include <cstdio>
#include "Thread.hpp"int ticket = 10000;std::string ThreadName()
{static int number = 1;char name[64];snprintf(name, sizeof(name), "Thread[%d]", number);return name;
}void BuyTicket(int mutex)
{while (true){if (ticket > 0){usleep(1000); // 假设访问花费的时间ticket--;printf("剩余票数:%d\n", ticket);}else{break;}}
}int main()
{std::vector<Thread<int>> Ts;for (int i = 0; i < 5; i++){// Thread(const std::string &tname, Func_t<T> func, T data)std::string name = ThreadName();Thread<int> tmp(name, BuyTicket, 0);Ts.push_back(tmp);}for (int i = 0; i < 5; i++){Ts[i].Start();}for (int i = 0; i < 5; i++){Ts[i].Join();}return 0;
}
这里我们模拟了五个线程,抢10000张票
运行结果是这样的

这里出现了离谱的情况,我们明明设置了,当票数检测到小于等于0时会跳出循环
但是还是依然抢到了剩下的票
如果我们直观理解的话,其实就是在判断的时候,在五个线程都只剩下了1张票时,几乎同时进了这个判断
然后再轮流执行导致了票数减少
要解决这样的问题就需要互斥锁
因为票是共享的,有限的资源,需要对其进行保护
下一篇我们会介绍Linux线程互斥和同步的实现方法
相关文章:
Linux多线程——利用C++模板对pthread线程库封装
文章目录 线程封装主要框架线程启动线程等待其他信息 测试函数 线程封装 我们之前介绍过pthread的线程库,这个线程库主要是基于C语言的void*指针来进行传参和返回 我们使用C的模板对其封装可以让他的使用更加方便,并且经过测试可以让我们更加直观的了解…...
SpringBoot教程(十五) | SpringBoot集成RabbitMq(消息丢失、消息重复、消息顺序、消息顺序)
SpringBoot教程(十五) | SpringBoot集成RabbitMq(消息丢失、消息重复、消息顺序、消息顺序) RabbitMQ常见问题解决方案问题一:消息丢失的解决方案(1)生成者丢失消息丢失的情景解决方案1…...
TensorRT-LLM高级用法
--multi_block_mode decoding phase, 推理1个新token, 平时:按照batch样本,按照head,将计算平均分给所有SM; batch_size*num_heads和SM数目相比较小时:有些SM会空闲;加了--multi_block_mode&…...
文心一言功能新升级:读文档、懂翻译、能识图
9月4日,百度文心一言官网显示,在向全社会开放一周年之际,文心一言进行了功能最新全面升级,同时在周年期间为新老会员增加1个月专业版免费使用体验。 据了解,针对网页版用户需求,文心一言实现了创作内容更加…...
C++机试——走方格的方案
题目 请计算n*m的棋盘格子(n为横向的格子数,m为竖向的格子数)从棋盘左上角出发沿着边缘线从左上角走到右下角,总共有多少种走法,要求不能走回头路,即:只能往右和往下走,不能往左和往…...
Bootstrap 字体图标无法显示问题,<i>标签字体图标无法显示问题
bootstrap fileInput 以及 Bootstrap 字体图标无法显示问题。 今天在用 bootstrap fileInput 插件的时候发现图标无法显示,如下: 查看DOM,发现那些图标是<i>标签做的: 网上的方案 方案1 网上很多人说是我们打乱了boots…...
docker registry 仓库加密
docker registry 仓库加密 1、背景 公司一直用的镜像仓库是docker registry,但是有个安全问题,就是仓库从web ui的浏览到镜像的拉取都是可以直接使用的,还是放到了公网上,只需要知道你的域名那就是畅通无阻了,可以…...
利用高德+ArcGIS优雅获取任何感兴趣的矢量边界
荷花十里,清风鉴水,明月天衣。 四时之景不同,乐亦无穷尽也。今天呢,梧桐君给大家讲解一下,如何利用高德地图,随机所欲的获取shp边界数据。 文章主要分成以下几个步骤: 首先搜索你想获取的矢量…...
炮弹【USACO】
题目背景 时/空限制:1s / 64MB 题目描述 贝茜已经精通了变成炮弹并沿着长度为 N 的数轴弹跳的艺术,数轴上的位置从左到右编号为 1,2,…,N 。 她从某个整数位置 S 开始,以 1 的起始能量向右弹跳。 如果贝茜的能量为 k ,则她将…...
python如何读取excel文件内的数据
目录 前言一、安装openpyxl二、读取Excel数据总结前言 在Python中读取Excel数据,最常用的库之一是openpyxl(用于.xlsx格式)和xlrd(尽管xlrd从版本2.0开始不再支持.xlsx,仅支持旧的.xls格式)。然而,对于大多数现代应用来说,openpyxl是一个更好的选择,因为它支持.xlsx格…...
Java项目: 基于SpringBoot+mybatis+maven+mysql教师工作量管理系统(含源码+数据库+毕业论文)
一、项目简介 本项目是一套基于SpringBootmybatismavenmysql教师工作量管理系统 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试,eclipse或者idea 确保可以运行! 该系统功能完善、界面美观…...
项目开发--数据库--postgresql数据库操作
背景 1、安装postgresql的基础方法 2、基本操作命令 解决方案 安装命令 在ubuntu环境当中进行安装。 sudo apt install postgresql安装完毕之后直接进行测试,如果看到如下内容则安装成功。 sudo systemctl status postgresql使用DBeaver进行连接报错ÿ…...
c语言——用一维数组输出杨辉三角形
一.代码 #include <stdio.h> int Num[100]; int Hang; int Lie; int a; int Flag; int main() {Lie 1;Hang 1;a 0;while (1) {//列1为1if (Lie 1) {Num[1] 1;Lie;}//数据存到数组里面while (Hang > Lie && Hang ! 2) { if (Hang!Lie) {Flag Num[Lie] …...
Codeforces Round 971 (Div. 4) (A~G1)
A、B题太简单,不做解释 C 对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。 由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案…...
为什么构造函数不能为虚函数?为什么析构函数可以为虚函数,如果不设为虚函数可能会存在什么问题?
目录 一、为什么构造函数不能为虚函数? 二、为什么析构函数可以是虚函数?如果不设为虚函数可能会存在什么问题? 构造函数不能为虚函数,因为在构造过程中,虚函数机制尚未生效,对象还未完成构造,…...
【数据结构】单链表功能的实现
目录 1.链表的概念及结构 2.单链表功能的实现 2.1打印单链表 2.2创建节点 2.3单链表尾插 2.3单链表头插 2.5单链表尾删 2.6单链表头删 2.7单链表的查找 2.8在指定位置之前插入数据 2.9在指定位置之后插入数据 2.10删除pos节点 2.11删除pos之后的节点 2.12销毁链表…...
最新车型库大全|阿里云实现调用API接口
整体请求流程: 介绍: 本次解析通过阿里云云市场的云服务来实现查询车型库大全查询,首先需要选择一家可以提供查询的商品。 [探数API]车型库查询_API专区_云市场-阿里云 步骤1: 选择商品 如图点击免费试用,即可免费申请该接口数…...
70. 爬楼梯
70. 爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 输入:n 2 输出:2 解释:有两种方法可以爬到楼顶。 1.1 阶 1 阶 2.2 阶 示例…...
pytorch正向传播没问题,loss.backward()使定义的神经网络中权重参数变为nan
记录一个非常坑爹的bug:loss回传导致神经网络中一个linear层的权重参数变为nan 1.首先loss值是正常数值; 2.查了好多网上的解决办法:检查原始输入神经网络数据有没有nan值,初始化权重参数,使用relu激活函数,梯度裁剪&a…...
❤《实战纪录片 1 》原生开发小程序中遇到的问题和解决方案
《实战纪录片 1 》原生开发小程序中遇到的问题和解决方案 文章目录 《实战纪录片 1 》原生开发小程序中遇到的问题和解决方案1、问题一:原生开发中 request请求中返回 的数据无法 使用this传递给 data{}中怎么办?2、刚登录后如何将token信息保存…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
