【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 提供了比较完善的后台管理数据库的接…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...















