Linux多线程——利用C++模板对pthread线程库封装

news2024/11/13 19:38:07

文章目录

    • 线程封装
      • 主要框架
      • 线程启动
      • 线程等待
      • 其他信息
    • 测试函数

线程封装

我们之前介绍过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线程互斥和同步的实现方法

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

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

相关文章

DPDK基础入门(二):Cache与大页优化

Cache简介 目前Cache主要由三级组成: L1 Cache, L2 Cache和Last Level Cache(LLC)。 L1最快&#xff0c;但容量小&#xff0c;可能只有几十KB。LLC慢&#xff0c;但容量大&#xff0c;可能多达几十MB。 L1和L2 Cache一般集成在CPU内部。另外,&#xff0c;L1和L2 Cache是每个处…

【2024】Datawhale X 李宏毅苹果书 AI夏令营 Task3

本文是关于李宏毅苹果书”第2章 实践方法论“学习内容的记录。 模型在测试集上表现不佳&#xff0c;可能是因为模型没有充分学习训练集。模型不能充分学习训练集的原因&#xff1a; 模型偏差优化问题过拟合不匹配 一、模型偏差 模型偏差是指&#xff1a;由于模型过于简单&a…

网站如何针对不同的DDOS进行防御?

建设网站租用服务器是多数企业及个人的选择&#xff0c;一个安全稳定的服务器对网站的重要性无需再赘述。要保证服务器租用的安全和稳定&#xff0c;除了需要服务器自身有强大的硬、软件基础之外&#xff0c;还需要防范外部的一些因素&#xff0c;常见的就是各种网络攻击&#…

Linux 上如何做MySQL数据备份

目录 SQL备份脚本创建crontabcrontab命令总结查看特定目录中的周期性任务 crontab&#xff08;cron table 的缩写&#xff09;是 Unix/Linux 系统上用于设置周期性被执行的任务的工具。它允许用户定义需要在特定时间&#xff08;比如每天凌晨、每周的某个时间等&#xff09;自动…

驭势科技研究成果入选学术顶会IROS 2024

近日&#xff0c;驭势科技团队关于自动驾驶车辆定位算法的最新研究成果《LiDAR-based HD Map Localization using Semantic Generalized ICP with Road Marking Detection》&#xff0c;创造性地解决了基于LiDAR的实时路标检测和高精地图配准所带来的挑战&#xff0c;成功入选国…

汇川技术|KingIOServer与AC810PLC通过ModbusTCP通讯测试

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 最近有个项目用亚控的KingSCADA软件开发SCADA系统&#xff0c;需要和汇川的AC810PLC进行通讯&#xff1b; 本节测试亚控的采集软件KingIOServer与汇川的AC810PLC的通讯测试。 以下为测试笔记。 01 效果演示 测试过程…

3个苹果锁屏密码解锁方法,帮你快速解决密码忘记的烦恼!

苹果手机锁屏密码忘记了是一件很常见的问题&#xff0c;但也是一件让人头疼的事情。如果你遇到了这样的问题&#xff0c;不要着急&#xff0c;因为有很多方法可以帮助你解锁iPhone。下面我们将介绍四种简单的方法来解锁iPhone。 一、使用密码解锁工具 iphone忘记了密码怎么解锁…

iconfont图标字体库详细介绍

概述 图标库在前端开发中应用十分广泛&#xff0c;图标库不仅会丰富美化界面的展示&#xff0c;语义化的图标库更能简洁明了地向用户传达某些信息&#xff0c;比如功能的特性和作用&#xff0c;引导用户&#xff0c;极大提高系统的易用性。在没有 UI 设计师的情况下&#xff0…

【C++】手动实现队列的封装(C++)

目录 源代码&#xff1a; 输出结果如下&#xff1a; 实现以下封装 源代码&#xff1a; #include <iostream>using namespace std;class Queue { private:int* arr; // 队列的动态数组int front; // 队列头部元素的索引int rear; // 队列尾部元素的索引in…

新版某数字壳脱壳,过frida检测,及重打包

目录 脱壳 寻找特征& frida hook 过frida检测 修复dex 重打包 修改smail 去签名校验 正文 大家好&#xff0c;我是小生&#xff0c;这次的app是一个国内某计划app, 功能相当全&#xff0c;界面也很美观&#xff0c;很实用&#xff0c;这个app我很欣赏。总共花了有…

【SQL】Delete使用

目录 语法 需求 示例 分析 代码 语法 DELETE删除表中所需内容 删除表中满足特点条件的行&#xff1a;DELETE FROM 表名 WHERE 条件; 删除表中所有行&#xff1a;DELETE FROM 表名; WHERE子句 WHERE子句用于指定从表中选取记录的条件。允许筛选数据&#xff0c;只返回满足…

【文献精读】基于驱动力表的无人车终端无约束预测纵向控制(TVT)

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

ElasticSearch学习笔记(六)自动补全、拼音分词器、RabbitMQ实现数据同步

文章目录 前言11 自动补全11.1 拼音分词器11.2 自定义分词器11.3 自动补全查询 12 数据同步12.1 实现方案12.1.1 同步调用12.1.2 异步通知12.1.3 监听binlog 12.2 异步通知实现数据同步12.2.1 声明交换机和队列12.2.2 发送MQ消息12.2.3 接收MQ消息并操作ES 前言 ElasticSearch…

数据结构————单向链表

头插&#xff1a; 尾插&#xff1a; 头删&#xff1a; 尾删&#xff1a;

一种常用嵌入式开发代码库

链接&#xff1a;https://gitee.com/zhangxinyuanqi/varch 使用开源协议&#xff1a;GPL-2.0 varch简介 varch&#xff08;we-architecture&#xff0c;意为我们的框架库&#xff09;是嵌入式C语言常用代码模块库&#xff0c;包含了嵌入式中常用的算法库, 数据结构&#xff…

JPA关联MyBatis

3.1 JPA 多表查询 多表查询在 Spring Data JPA 中有两种实现方式&#xff0c;第一种是创建一个结果集的接口来接受多表连接查询后的结果&#xff0c;第二种是利用 JPA 的关联映射来实现 3.1.1 数据库表及关系 CRM 数据库中除 sys_user(用户)表外&#xff0c;还包括sys_role(角…

触想内嵌式工业一体机应用于智能检票机改善旅游体验

一、行业发展背景 每年下半年&#xff0c;暑假、中秋、国庆总是接踵而至&#xff0c;随之而来的出游高峰一波接一波。凶猛需求之下&#xff0c;各地景区、游乐园客流压力加大&#xff0c;特别在检票环节&#xff0c;人工检票效率低、秩序混乱&#xff0c;导致常常出现检票口人山…

POL(Point-of-Load)负载点电源

负载点&#xff08;POL&#xff09;电源在靠近负载处单独放置电源调节器(线性稳压器或DC-DC)&#xff0c;解决了高性能半导体器件&#xff0c;例如&#xff1a;微控制器、ASIC等&#xff0c;所面临的高峰值电流、低噪声裕量等设计挑战。 一般我们会把负载点电源尽量靠近负载放…

乾元通多卡聚合技术在无人配送车应用领域通信保障方案

在无人驾驶公交车、安防车、售卖车、清扫车相继亮相后&#xff0c;无人配送车在全国各地也陆续“上岗”&#xff0c;为我们的城市带来了与众不同的“智慧体验”&#xff0c;让城市有了“科技温度”。 无人配送车在营业部装载好快递后&#xff0c;会按照提前规划好的路线出发&a…

sqli-labs靶场通关攻略 61-65

主页有sqli-labs靶场通关攻略 1-60 第六一关 less-61 步骤一&#xff1a;闭合方式&#xff1a;?id1)) -- 步骤二&#xff1a;查询数据库 ?id1)) and updatexml(1,concat(1,database()),1) -- 步骤三&#xff1a;查出网站的数据库表名 ?id1)) and updatexml(1,concat(0x7e…