【Linux系统编程】第四十四弹---从TID到线程封装:全面掌握线程管理的核心技巧

个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】

目录

1、tid是什么

1.1、理解库 

1.2、理解tid

1.3、tid中线程局部存储

2、封装线程 

2.1、基本结构

2.2、函数实现

2.3、使用单线程

2.4、使用多线程


1、tid是什么

从前面的讲解我们猜测tid是一个虚拟地址,并使用代码打印出来,此处需要更进一步分析tid,先代码演示一下!!!

用到的头文件

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <string>
#include <cstdio>

 代码演示

std::string ToHex(pthread_t tid)
{char id[128];snprintf(id,sizeof(id),"0x%lx",tid);return id;
}void* threadrun(void* args)
{std::string name = static_cast<const char*>(args);while(true){// std::cout << name << " is running...,tid: " << pthread_self() << std::endl; std::cout << name << " is running...,tid: " << ToHex(pthread_self()) << std::endl; sleep(1);}
}int main()
{pthread_t tid;pthread_create(&tid,nullptr,threadrun,(void*)"thread-1");// std::cout << "new thread tid: " << tid << std::endl;std::cout << "new thread tid: " << ToHex(tid) << std::endl;pthread_join(tid,nullptr);return 0;
}

运行结果 

1.1、理解库 

 讲解tid之前我们需要先理解一下库

1、库是一个文件,保存在磁盘中,然后将库加载到内存,再通过页表将库映射到地址空间中

2、创建线程,前提是把库加载到内存,映射到进程的内存空间

3、创建线程,调用线程库中的系统调用函数

1.2、理解tid

库是如何做到对线程进行管理的呢?

先描述(库中创建描述线程的相关结构体字段属性),在组织("数组")。

如何理解这个虚拟地址?

可以类比C语言打开文件,通过地址找到文件!!!

tid是什么? 

线程属性集合的起始虚拟地址--- 在pthread库中维护

1.3、tid中线程局部存储

编写C++代码

int gval = 100;std::string ToHex(pthread_t tid)
{char id[128];snprintf(id, sizeof(id), "0x%lx", tid);return id;
}void *threadrun(void *args)
{std::string name = static_cast<const char *>(args);while (true){std::string id = ToHex(pthread_self());std::cout << name << " is running...,tid: " << id << ",gval: " << gval << ",&gval: " << &gval << std::endl;sleep(1);gval++;}
}int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadrun, (void *)"thread-1");while (true){std::cout << "main thread,gval: " << gval << ",&gval: " << &gval << std::endl;sleep(1);}pthread_join(tid, nullptr);return 0;
}

运行结果  

 如果想要每个线程使用独立的内存空间呢?

__thread (两个下划线)修饰全局变量,即在线程局部存储中开辟空间!!!

  • 定义:__thread是GCC内置的线程局部存储设施,用于创建线程局部变量
  • 作用保证每个线程拥有独立的变量副本,各个线程对该变量的操作互不干扰。
// Linux有效, __thread只能修饰内置类型
__thread int gval = 100;

 运行结果 

2、封装线程 

2.1、基本结构

线程的封装可以使用命名空间域,类成员变量有name,tid,isrunning,func!!!

namespace ThreadMoudle
{// 线程要执行的方法typedef void (*func_t)(const std::string& name); // 函数指针类型class Thread{public:// 执行回调函数void Excute();public:Thread(const std::string& name,func_t func):_name(name),_func(func);// 新线程执行该方法static void* ThreadRoutine(void* args);// 线程状态std::string Status();// 启动线程bool Start();// 停止线程void Stop();// 线程名字std::string Name();// 等待线程void Join();~Thread();private:std::string _name; // 线程名pthread_t _tid; // 线程tidbool _isrunning; // 线程状态func_t _func; // 线程要执行的回调函数};
}

2.2、函数实现

构造函数

打印一条语句即可!

Thread(const std::string& name,func_t func):_name(name),_func(func)
{std::cout << "create " << _name << " done" << std::endl;
}

启动线程

启动线程的本质是创建一个新线程,创建成功返回true,创建失败返回false。

1、创建新线程需要调用执行函数,但是成员函数会有隐含的this指针,直接调用成员函数会报错,因为执行函数只能有一个参数,解决办法是使用静态成员函数,该函数属于类,不属于对象,因此没有隐含的this指针。

2、使用静态成员函数之后,没有this指针,就不能直接调用类对象的方法,此处的解决办法是将this指针传给执行函数。

void Excute()
{std::cout << _name << " is running" << std::endl;_isrunning = true;_func(_name);_isrunning = false;
}
// 新线程执行该方法
static void* ThreadRoutine(void* args)
{// _func(); // static 不能直接访问成员函数,没有this,传this指针Thread* self = static_cast<Thread*>(args);self->Excute();return nullptr;
}
bool Start()
{// ::使用库函数接口,直接使用ThreadRoutine会报错,因为成员函数有隐含this指针 + staticint n = ::pthread_create(&_tid,nullptr,ThreadRoutine,this);if(n != 0) return false;return true;
}

停止线程

如果线程处于运行状态则需要停止线程,停止的本质是取消线程,修改线程运行状态即可!

void Stop()
{if(_isrunning){::pthread_cancel(_tid);_isrunning = false;std::cout << _name << " Stop" << std::endl;}
}

等待线程

 等待线程即调用等待线程的系统调用即可!

void Join()
{::pthread_join(_tid,nullptr);std::cout << _name << " Join" << std::endl;
}

其他函数 

std::string Status()
{if(_isrunning)return "running";else return "sleep";
}
std::string Name()
{return _name;
}
~Thread()
{}

2.3、使用单线程

自己管理单线程!! 先描述在组织!!!

void Print(const std::string &name)
{int cnt = 1;while (true){std::cout << name << " is running,cnt: " << cnt++ << std::endl;sleep(1);}
}int main()
{Thread t("thread-1", Print);t.Start();sleep(1); // 等待一秒,因为线程执行顺序不确定,可能主线程后执行std::cout << t.Name() << ",status: " << t.Status() << std::endl;sleep(10);t.Stop();sleep(1);std::cout << t.Name() << ",status: " << t.Status() << std::endl;t.Join();std::cout << t.Name() << ",status: " << t.Status() << std::endl;return 0;
}

 

2.4、使用多线程

要使用多线程,实质就是创建多个线程,然后将多线程管理起来,我们可以使用vector容器!

新线程执行函数 

void Print(const std::string &name)
{int cnt = 1;while (true){std::cout << name << " is running,cnt: " << cnt++ << std::endl;sleep(1);}
}

主函数 

const int gnum = 10;int main()
{std::vector<Thread> threads;// 创建线程for(int i=0;i<gnum;i++){std::string name = "thread" + std::to_string(i+1);threads.emplace_back(name,Print);sleep(1);}// 统一启动for(auto& thread : threads){thread.Start();}sleep(3);// 统一停止for(auto& thread : threads){thread.Stop();}// 统一等待for(auto& thread : threads){thread.Join();}return 0;
}

运行结果 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智慧城市路面垃圾识别系统产品介绍方案

方案介绍 智慧城市中的路面垃圾识别算法通常基于深度学习框架&#xff0c;这些算法因其在速度和精度上的优势而被广泛采用。这些模型能够通过训练识别多种类型的垃圾&#xff0c;包括塑料袋、纸屑、玻璃瓶等。系统通过训练深度学习模型&#xff0c;使其能够识别并定位多种类型…

大模型人工智能课程全栈完整学习路径

嘿&#xff0c;朋友们&#xff0c;今天我们聊点高级的——大模型人工智能课程的全栈学习路径。不过别慌&#xff0c;虽然听起来高大上&#xff0c;但咱们慢慢来。从零开始&#xff0c;一步步带你走进这个神奇的世界。喝杯咖啡&#xff0c;穿上最舒适的拖鞋&#xff0c;准备好踏…

「Mac畅玩鸿蒙与硬件32」UI互动应用篇9 - 番茄钟倒计时应用

本篇将带你实现一个番茄钟倒计时应用&#xff0c;用户可以设置专注时间和休息时间的时长&#xff0c;点击“开始专注”或“开始休息”按钮启动计时&#xff0c;应用会在倒计时结束时进行提醒。番茄钟应用对于管理时间、提升工作效率非常有帮助&#xff0c;并且还会加入猫咪图片…

STM32H503开发(1)----开发板测试

STM32H503开发----1.开发板测试 概述硬件准备视频教学样品申请源码下载产品特性参考程序生成STM32CUBEMX串口配置LED配置堆栈设置串口重定向主循环演示 概述 STM32H503 & SENSOR是一款基于STM32H5系列微控制器的评估套件。该微控制器采用了40nm工艺制造&#xff0c;具有更…

HTB:Perfection[WriteUP]

目录 连接至HTB服务器并启动靶机 1.What version of OpenSSH is running? 使用nmap对靶机TCP端口进行开放扫描 2.What programming language is the web application written in? 使用浏览器访问靶机80端口页面&#xff0c;并通过Wappalyzer查看页面脚本语言 3.Which e…

SDL打开YUV视频

文章目录 问题1&#xff1a;如何控制帧率&#xff1f;问题2&#xff1a;如何触发退出事件&#xff1f;问题3&#xff1a;如何实时调整视频窗口的大小问题4&#xff1a;YUV如何一次读取一帧的数据&#xff1f; 问题1&#xff1a;如何控制帧率&#xff1f; 单独用一个子线程给主线…

Android V 挂起线程超时导致system_server挂掉

问题背景 最近Android v的平台频繁爆monkey异常停止的问题,分析到根因不是频繁dump堆栈导致system_server挂掉就是三方应用进程内部死锁导致anr,然后system_server挂起线程超时,system_server就崩了。 解决方案 先来看看anr导致死锁的场景如何分析 从log来看确认为syste…

下载mysql的jar,添加至jmeter中,编写jdbc协议脚本1106

下载jar包&#xff1a; 步骤1&#xff1a;进入maven仓库官网https://mvnrepository.com/ 步骤2&#xff1a;搜索实际的数据库 步骤3&#xff1a;点击 Mysql connnector/J 步骤5、查看数据库的版本号&#xff0c;选择具体版本&#xff0c;我的是mysql 8.0.16,下图&#xff0c;…

【分布式】分布式锁设计与Redisson源码解析

分布式锁 分布式锁是一种在分布式计算环境中用于控制多个节点&#xff08;或多个进程&#xff09;对共享资源的访问的机制。在分布式系统中&#xff0c;多个节点可能需要协调对共享资源的访问&#xff0c;以防止数据的不一致性或冲突。分布式锁允许多个节点在竞争访问共享资源…

CAD 图元 动一下消失

Z.ed.DrawVector(Point3d.Origin, new Point3d(100, 100, 0), 1, true);

【计网】实现reactor反应堆模型 --- 处理数据发回问题 ,异常处理问题

没有一颗星&#xff0c; 会因为追求梦想而受伤&#xff0c; 当你真心渴望某样东西时&#xff0c; 整个宇宙都会来帮忙。 --- 保罗・戈埃罗 《牧羊少年奇幻之旅》--- 实现Reactor反应堆模型 1 数据处理2 数据发回问题3 异常处理问题4 运行效果 1 数据处理 在上一篇文章中我…

Science Robotics 综述揭示演化研究新范式,从机器人复活远古生物!

在地球46亿年的漫长历史长河中&#xff0c;生命的演化过程充满着未解之谜。如何从零散的化石证据中还原古生物的真实面貌&#xff1f;如何理解关键演化节点的具体过程&#xff1f;10月23日&#xff0c;Science Robotics发表重磅综述&#xff0c;首次系统性提出"古生物启发…

string接口的深度理解(内附思维导图)

1. 为什么学习string类&#xff1f; C语言中的字符串 C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列 的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP的思想&#xff0…

python可视化将多张图整合到一起(画布)

这周有点事忙着&#xff0c;没时间重温刚结束的Mathurcup数学建模&#xff0c;这两天也是再看了下&#xff0c;论文还是赶紧挺烂的&#xff0c;但比国赛又有进步&#xff08;说起国赛又不得不抱怨了&#xff0c;基本其余省份都发了&#xff0c;但江西......哎&#xff09;。哎&…

jsp+sevlet+mysql实现用户登陆和增删改查功能

jspsevletmysql实现用户登陆和增删改查功能 一、系统介绍二、功能展示1.用户登陆2.用户列表3.查询用户信息4.添加用户信息5.修改用户信息6.删除用户信息 四、其它1.其他系统实现 一、系统介绍 系统主要功能&#xff1a; 用户登陆、添加用户、查询用户、修改用户、删除用户 二…

Python小白学习教程从入门到入坑------第二十九课 访问模式文件定位操作(语法进阶)

一、访问模式 模式可做操作若文件不存在是否覆盖r只能读报错-r可读可写报错是w只能写创建是w可读可写创建是a只能写创建否&#xff0c;追加写a可读可写创建否&#xff0c;追加写 1.1 r r&#xff1a;只读模式(默认模式)&#xff0c;文件必须存在&#xff0c;不存在就会报错…

TIOBE 编程指数 11 月排行榜公布 VB.Net第九

IT之家 11 月 9 日消息&#xff0c;TIOBE 编程社区指数是一个衡量编程语言受欢迎程度的指标&#xff0c;评判的依据来自世界范围内的工程师、课程、供应商及搜索引擎&#xff0c;今天 TIOBE 官网公布了 2024 年 11 月的编程语言排行榜&#xff0c;IT之家整理如下&#xff1a; P…

聚合联盟的优势

聚合广告联盟对比其他平台优势&#xff1a; 数据透明&#xff0c;自己去平台查看不存在扣量问题。对OVHM做策略优化&#xff0c;帮助开发者做多重点击和下载&#xff0c;使开发者利益最大化。为开发者提供app各大市场上架&#xff0c;隐私协议等指导。 最大的优势就是数据公开…

FakeLocation 版本问题

前言:最新版的FakeLocation 1.3.5 BETA版本在appconfigs.xml文件种添加了绝大多数的应用,导致会返回真实的物理位置&#xff0c;在1.3.2.2都没有这个问题&#xff0c;但是旧版是会被强制更新&#xff0c;不然无法使用. 版本问题/注入/代理 方法 需要使用FakeLocation有二种办法…

算法(第一周)

一周周五&#xff0c;总结一下本周的算法学习&#xff0c;从本周开始重新学习许久未见的算法&#xff0c;当然不同于大一时使用的 C 语言以及做过的简单题&#xff0c;现在是每天一题 C 和 JavaScript&#xff08;还在学&#xff0c;目前只写了一题&#xff09; 题单是代码随想…