【Linux】线程的控制
目录
线程等待
线程退出
线程的优缺点
线程独占和共享的数据
我们说Linux是用进程模拟的线程,所以Linux中只有轻量级进程的概念,但是,用户是只认线程的,所以我们有一个叫原生线程库的东西,它就负责把轻量级进程的系统调用进行封装,转成线程相关的接口提供给用户。
为什么叫原生呢?就是说只要你装Linux系统,就必须装这个库,就是默认装好的库。
有关线程的接口在3号手册,就证明它们不是系统调用,因为系统调用在2号手册。当然也有创建轻量级进程的系统调用
man clone,它是在二号手册
我们可以说,其实pthread_create其实就是封装了这个系统调用
pthread_create创建新线程时第一个参数是输出型参数,会带回来一个id值,那么这个值和LWP之间是什么关系呢?我们可以断定的认为它们是一对一的关系,用户层使用id值,内核只用LWP,我们可以打印一下这个id值,我们可以把id值改成十六进制
这个值很大,其实它就是一个地址,位于栈和堆之间的共享区的一个地址,我们后面会有讲解
这是主进程获取新线程的id值,那么一个线程如何获取它自己的id值呢?
man pthread_self
这个函数就是谁调用它就获取谁的id值
我们从主线程和新线程中获取的新线程的id肯定是一样的
新线程和主线程谁先运行呢?这个是不确定的,是由调度器来决定的
pthread_create的第四个参数是给新线程要执行的函数传的参数,是void*类型,我们之前都传的是nullptr,我们可以传一个名字
新主线程大部分资源是共享的,比如地址空间是共享的,我如果定义一个全局变量,那么新主进程都可以看见
我们可以看到,新线程对于全局数据的修改,主线程也是可以看到的
线程等待
主线程如果退出的话,不管新线程是否退出,整个进程都会退出,意味着资源会释放,所有线程都会退出。所以我们往往要求主线程是最后退出的
并且线程也是要被等待的,否则会像进程那样发生内存泄漏的问题,线程等待就要用到下面这个接口
man pthread_join
这个接口也是默认是阻塞式等待的
第一个参数是要等待哪个线程
第二个参数是等待到了什么东西,因为新线程的返回值是void*类型的,所以要用void*类型去接收,它是一个输出型参数,所以我要传的参数是void*的指针,所以是void**
我们简单来用一下:
void *newthreadrun(void *args) {char *str = (char *)args;int cnt = 5;while (cnt--){cout << str << " is running " << endl;sleep(1);}return (void *)12345; } int main() {pthread_t tid;pthread_create(&tid, nullptr, newthreadrun, (void *)"pthread-1");void *ret = nullptr;int n = pthread_join(tid, &ret);if (n == 0){cout << " return val is: " << (long long)ret << endl;//指针64位下是8个字节,强转成long long不会损失精度}return 0; }
如果说线程出异常(比如除零),那么整个进程都会退出,这是因为信号是给进程发送的,一个线程出了问题,那么就是这个进程出了问题,整个进程都要被杀死。
所以我们普遍认为多进程的代码往往健壮性不好,当然这是普遍来说的,如果一个多线程的代码写的很好,健壮性也是不成问题的
所以pthread_join是不考虑新线程的异常情况的,因为只要异常,整个进程都退出了,根本不存在等待的问题;它只考虑代码运行完,结果是否正确
线程退出
如果对一个线程使用exit会怎样呢?它会使整个进程退出,因为exit本身就是用来终止进程的,而不是用来终止线程的
所以我们有一个pthread_exit用来终止线程
man pthread_exit
参数就是像return后面的数据一样,就是想返回什么
上面这种方法是新线程主动退出,那如果是主线程想让新线程退出该怎么办呢?可以用下面的接口
man pthread_cancel
这里如果取消掉新线程并且等待新线程,那么n==0,ret==-1,这里的-1 其实就是一个宏,表示线程被取消了
所以进程退出有三种方式,return,pthread_exit和pthread_cancel
线程的优缺点
优点:
1.创建一个新线程的代价比创建一个新进程小很多,因为创建一个线程只需要创建一个PCB,而进程需要地址空间,页表,文件描述表等等
2.与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
要解释这个,我们就不得不提到CPU中的cache(缓存)了,CPU要执行某行代码,不是只把这行代码放到CPU中,而是要把执行的代码及周围的代码都放到cache中,这样CPU要执行的下一条代码就很有可能已经在缓存中了,对于不同的线程切换来说,这是有几率命中的,但是对于不同的进程切换,肯定要换掉缓存中的代码
我们可以用lscpu看一下云服务器的CPU配置
3.IO操作基本大部分时间都是在等,所以我们可以趁着等的时间多创建几个线程执行其他的任务
缺点:
1.一般计算密集型的进程的线程数量和CPU的数量相同,如果线程数量太多,也会增加调度的开销
2.健壮性降低,线程之间缺乏保护就容易导致产生不良影响
3.编程难度提高,编写与调试一个多线程程序比单线程程序困难得多
线程独占和共享的数据
线程独占:
1.线程的硬件上下文(CPU寄存器内部的值)(从调度角度而言)
2.线程的独立栈结构(从常规运行的角度)
3.线程的ID
4.信号屏蔽字
5.调度优先级
6.errno变量
线程共享
1.函数和全局变量
2.文件描述符表
3.各种信号的处理方式
4.当前工作目录
5.用户id和组id(这些id标识了线程的拥有者和所属组)
我们如果想创建多个线程可以这样
void *newthreadrun(void *args) {char *str = (char *)args;int cnt=5;while(cnt--){cout << str << " is running " << endl;sleep(1);}delete[] str;//new[]的空间要delete[]return nullptr; } int main() {pthread_t tid;vector<pthread_t>f;for (int i = 1; i <= 5; i++){char*buffer=new char[64];//这里必须new,否则五个线程看到的是一块空间snprintf(buffer, 64, "pthread-%d", i);//不能用sizeof,因为sizeof(buffer)==8pthread_create(&tid, nullptr, newthreadrun, buffer);f.push_back(tid);}for(auto e:f){pthread_join(e,nullptr);}return 0; }
我们也可以将线程和C++中的类和对象联系应用起来
template<class T> T add(T x, T y) {return x + y; } template <class T> class threaddata { public:threaddata(const char *str, function<T(T, T)> task): _name(str), _task(task){delete[] str;}T Dotask(T x, T y){return _task(x, y);}string _name;function<T(T, T)> _task;T _result; };void *newthreadrun(void *args) {threaddata<int> *p = (threaddata<int> *)args;p->_result = p->Dotask(10, 20);cout << p->_name << " get result: " << p->_result << endl;delete p;return nullptr; }int main() {pthread_t tid;vector<pthread_t> f;for (int i = 1; i <= 5; i++){char *buffer = new char[64];snprintf(buffer, 64, "pthread-%d", i);threaddata<int> *ptd = new threaddata<int>(buffer, add<int>);pthread_create(&tid, nullptr, newthreadrun, ptd);f.push_back(tid);}for (auto e : f){pthread_join(e, nullptr);}return 0; }
相关文章:

【Linux】线程的控制
目录 线程等待 线程退出 线程的优缺点 线程独占和共享的数据 我们说Linux是用进程模拟的线程,所以Linux中只有轻量级进程的概念,但是,用户是只认线程的,所以我们有一个叫原生线程库的东西,它就负责把轻量级进程的系…...

Vue3自研开源Tree组件:人性化的拖拽API设计
针对Element Plus Tree组件拖拽功能API用的麻烦,小卷开发了一个API使用简单的JuanTree组件。拖拽功能用起来非常简单! 文章目录 使用示例allowDragallowDrop支持节点勾选支持dirty检测后台API交互 源码实现 使用示例 组件的使用很简单: 通过…...
MYSQL--触发器详解
触发器 1.触发器简介 触发器(trigger)是一个特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作( insert,delete, update…...
C++实用指南:Lambda 表达式的妙用
Lambda 表达式的灵活性和强大功能确实为编程提供了许多便利。但是我们发现许多开发者仍然无法灵活运用其便利,于是写了这篇文章。 Lambda 允许我们编写更简洁和灵活的代码。例如在处理网络请求时,我们经常需要确保响应与当前的状态或需求仍然相关。通过…...

FastAPI(七十八)实战开发《在线课程学习系统》接口开发-- 评论
源码见:"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 梳理下思路 1.判断是否登录 2.课程是否存在 3.如果是回复,查看回复是否存在 4.是否有权限 5.发起评论 首先新增pydantic模型 class Cour…...

基于springboot+vue+uniapp的居民健康监测小程序
开发语言:Java框架:springbootuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包&#…...
TypeScript基础【学习笔记】
一、TypeScript 开发环境搭建 下载并安装 Node.js使用 npm 全局安装 typescript 进入命令行输入:npm i -g typescript 创建一个 ts 文件使用 tsc 对 ts 文件进行编译 进入命令行进入 ts 文件所在目录执行命令:tsc xxx.ts 二、基本类型 类型声明 通过类型…...
树莓派物联网服务器搭建流程:集成 Node.js、InfluxDB、Grafana 和 MQTT 协议
目录 一、搭建准备 1. 硬件要求 2. 软件要求 二、技术栈概述 三、搭建步骤 1. 安装操作系统 2. 启动树莓派 3. 更新系统 4. 安装必要的软件 4.1 安装 Python 和 Flask 4.2 安装 Node.js 4.3 安装 Mosquitto(MQTT Broker) 4.4 安装 InfluxDB…...
typescript 断言
/* 断言 确定后期一定是某种格式 可用于表单大对象初始化是空,赋值时有具体字段。前期断言是会是某种格式 */interface obj {name: stringlocation: stringage?: number }// 会报错 // let data: obj { // // } let data: obj {} as obj; // 断言data会有obj里…...

期刊评价指标及其查询方法
1、期刊评价体系一 科睿唯安《期刊引证报告》(Journal Citation Reports, JCR) 科睿唯安每年发布的《期刊引证报告》(Journal Citation Reports, JCR)是一个独特的多学科期刊评价工具。JCR数据库提供基于引文数据的统计信息的期…...

巴斯勒相机(Basler) ACE2 dart 系列说明和软件
巴斯勒相机(Basler) ACE2 dart 系列说明和软件...
【Pycharm中anaconda使用介绍】
在安装好anaconda之后,首先打开anaconda界面,执行以下操作 1.查看Anaconda中当前存在的环境 conda info -e 或者 conda-env list 查看–安装–更新–删除包 conda list: conda search package_name 查询包 conda install package_name conda …...

2024下半年,前端的技术风口来了
“ 你近期有体验过哪些大模型产品呢? 你有使用大模型API做过一些实际开发吗? 在你日常开发中,可以与大模型相关应用结合来完成工作吗? ” **最近,一直在和同事聊,关于前端可以用大模型干点啥ÿ…...

Spock Unit Test in Java
优质博文:IT-BLOG-CN 一、简介 Spock是一个基于Groovy语言的测试和规范框架,使得测试代码更简介,得益于JUnit Runner,Spock兼容大部分IDE和测试框架JUnit/JMock/Powermock等。基于BDD行为驱动开发,功能非常强大。提…...
:= 符号python
在 Python 3.8 及更高版本中,引入了一种新的语法特性,称为"海象运算符"(Walrus Operator),它使用 : 符号。这个运算符的主要目的是在表达式中同时进行赋值和返回赋值的值。 使用海象运算符可以在一些情况下…...

UPLOAD-LABS靶场[超详细通关教程,通关攻略]
---------------------------------------- 靶场环境: 下载链接: https://codeload.github.com/c0ny1/upload-labs/zip/refs/heads/master 使用小皮集成环境来完成这个靶场 将文件放到WWW目录下就可以进行访问 ------------------------------------…...
测试面试宝典(三十七)—— 接口测试中的加密参数如何处理?
1)先了解接口使用的加密方式(md5、rsa...) 2)检查接口测试工具是否支持这种加密方式,如果支持的话,直接使用对应功能就行了(比如Jmeter支持md5);如果加密方式是公司内部特有的算法,可以在接口测试工具中调…...

秋招突击——7/23——百度提前批面试准备和正式面试
文章目录 引言一面准备面试预演一1、讲一下hashcode()和equals()关系2、equals()和有什么区别3、讲一下重载和重写的区别4、讲一下深拷贝、浅拷贝的区别5、讲一下Java异常的基类,运行时异常举几个例子,什么情况下会出现?6、讲一下Java中线程的…...

学习日记:数据类型2
目录 1.转义字符 2.隐式类型转换 2.1 强制类型转换 2.2 不同类型间赋值 3.运算符 表达式 3.1 算术运算符 3.2 算术运算优先级 3.3 赋值运算 3.3.1 不同类型间混合赋值 3.4 逗号运算 4.生成随机数 5. 每日一练 1.转义字符 \n 表示换行 \t …...
Django Web框架——05
文章目录 admin 后台数据库管理注册自定义模型类修改自定义模型类的展现样式模型管理器类再谈Meta类 数据表关联关系映射一对一映射一对多映射多对多映射 cookies 和 sessioncookiessessionCookies vs session admin 后台数据库管理 django 提供了比较完善的后台管理数据库的接…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...

云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...