【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 提供了比较完善的后台管理数据库的接…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...















