当前位置: 首页 > news >正文

【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是用进程模拟的线程&#xff0c;所以Linux中只有轻量级进程的概念&#xff0c;但是&#xff0c;用户是只认线程的&#xff0c;所以我们有一个叫原生线程库的东西&#xff0c;它就负责把轻量级进程的系…...

Vue3自研开源Tree组件:人性化的拖拽API设计

针对Element Plus Tree组件拖拽功能API用的麻烦&#xff0c;小卷开发了一个API使用简单的JuanTree组件。拖拽功能用起来非常简单&#xff01; 文章目录 使用示例allowDragallowDrop支持节点勾选支持dirty检测后台API交互 源码实现 使用示例 组件的使用很简单&#xff1a; 通过…...

MYSQL--触发器详解

触发器 1.触发器简介 触发器&#xff08;trigger&#xff09;是一个特殊的存储过程&#xff0c;它的执行不是由程序调用&#xff0c;也不是手工启动&#xff0c;而是由事件来触发&#xff0c;比如当对一个表进行操作&#xff08; insert&#xff0c;delete&#xff0c; update…...

C++实用指南:Lambda 表达式的妙用

Lambda 表达式的灵活性和强大功能确实为编程提供了许多便利。但是我们发现许多开发者仍然无法灵活运用其便利&#xff0c;于是写了这篇文章。 Lambda 允许我们编写更简洁和灵活的代码。例如在处理网络请求时&#xff0c;我们经常需要确保响应与当前的状态或需求仍然相关。通过…...

FastAPI(七十八)实战开发《在线课程学习系统》接口开发-- 评论

源码见&#xff1a;"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 梳理下思路 1.判断是否登录 2.课程是否存在 3.如果是回复&#xff0c;查看回复是否存在 4.是否有权限 5.发起评论 首先新增pydantic模型 class Cour…...

基于springboot+vue+uniapp的居民健康监测小程序

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…...

TypeScript基础【学习笔记】

一、TypeScript 开发环境搭建 下载并安装 Node.js使用 npm 全局安装 typescript 进入命令行输入&#xff1a;npm i -g typescript 创建一个 ts 文件使用 tsc 对 ts 文件进行编译 进入命令行进入 ts 文件所在目录执行命令&#xff1a;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&#xff08;MQTT Broker&#xff09; 4.4 安装 InfluxDB…...

typescript 断言

/* 断言 确定后期一定是某种格式 可用于表单大对象初始化是空&#xff0c;赋值时有具体字段。前期断言是会是某种格式 */interface obj {name: stringlocation: stringage?: number }// 会报错 // let data: obj { // // } let data: obj {} as obj; // 断言data会有obj里…...

期刊评价指标及其查询方法

1、期刊评价体系一 科睿唯安《期刊引证报告》&#xff08;Journal Citation Reports, JCR&#xff09; 科睿唯安每年发布的《期刊引证报告》&#xff08;Journal Citation Reports, JCR&#xff09;是一个独特的多学科期刊评价工具。JCR数据库提供基于引文数据的统计信息的期…...

巴斯勒相机(Basler) ACE2 dart 系列说明和软件

巴斯勒相机(Basler) ACE2 dart 系列说明和软件...

【Pycharm中anaconda使用介绍】

在安装好anaconda之后&#xff0c;首先打开anaconda界面&#xff0c;执行以下操作 1.查看Anaconda中当前存在的环境 conda info -e 或者 conda-env list 查看–安装–更新–删除包 conda list&#xff1a; conda search package_name 查询包 conda install package_name conda …...

2024下半年,前端的技术风口来了

“ 你近期有体验过哪些大模型产品呢&#xff1f; 你有使用大模型API做过一些实际开发吗&#xff1f; 在你日常开发中&#xff0c;可以与大模型相关应用结合来完成工作吗&#xff1f; ” **最近&#xff0c;一直在和同事聊&#xff0c;关于前端可以用大模型干点啥&#xff…...

Spock Unit Test in Java

优质博文&#xff1a;IT-BLOG-CN 一、简介 Spock是一个基于Groovy语言的测试和规范框架&#xff0c;使得测试代码更简介&#xff0c;得益于JUnit Runner&#xff0c;Spock兼容大部分IDE和测试框架JUnit/JMock/Powermock等。基于BDD行为驱动开发&#xff0c;功能非常强大。提…...

:= 符号python

在 Python 3.8 及更高版本中&#xff0c;引入了一种新的语法特性&#xff0c;称为"海象运算符"&#xff08;Walrus Operator&#xff09;&#xff0c;它使用 : 符号。这个运算符的主要目的是在表达式中同时进行赋值和返回赋值的值。 使用海象运算符可以在一些情况下…...

UPLOAD-LABS靶场[超详细通关教程,通关攻略]

---------------------------------------- 靶场环境&#xff1a; 下载链接&#xff1a; https://codeload.github.com/c0ny1/upload-labs/zip/refs/heads/master 使用小皮集成环境来完成这个靶场 将文件放到WWW目录下就可以进行访问 ------------------------------------…...

测试面试宝典(三十七)—— 接口测试中的加密参数如何处理?

1&#xff09;先了解接口使用的加密方式(md5、rsa...) 2&#xff09;检查接口测试工具是否支持这种加密方式&#xff0c;如果支持的话&#xff0c;直接使用对应功能就行了(比如Jmeter支持md5)&#xff1b;如果加密方式是公司内部特有的算法&#xff0c;可以在接口测试工具中调…...

秋招突击——7/23——百度提前批面试准备和正式面试

文章目录 引言一面准备面试预演一1、讲一下hashcode()和equals()关系2、equals()和有什么区别3、讲一下重载和重写的区别4、讲一下深拷贝、浅拷贝的区别5、讲一下Java异常的基类&#xff0c;运行时异常举几个例子&#xff0c;什么情况下会出现&#xff1f;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 提供了比较完善的后台管理数据库的接…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...