系统编程--线程

这里写目录标题

  • 线程概念
    • 什么是线程
      • 简介
      • 图解
    • 内核原理
      • 图解
    • 线程共享资源与非共享资源
      • 共享资源
      • 非共享资源
    • 线程优缺点
  • 线程控制原语
    • pthread_self、pthread_create
      • 简介
      • 代码
      • 总结
    • 循环创建多个子线程
      • 错误代码
    • 线程间全局变量共享
    • pthread_exit
      • 简介
      • 代码
    • pthread_join(回收线程)
      • 简介
      • 代码
    • pthread_cancel
      • 简介
      • 代码
  • 一级目录
    • 二级目录
    • 二级目录
    • 二级目录
  • 一级目录
    • 二级目录
    • 二级目录
    • 二级目录
  • 一级目录
    • 二级目录
    • 二级目录
    • 二级目录

线程概念

什么是线程

简介

在这里插入图片描述

图解

在这里插入图片描述
对于一个进程来说,他有独立的进程地址空间,如上图左侧0~4G的进程地址空间,且他有一个PCB进程控制块

而当该进程调用pthread_create()创建线程时,这个线程不会再有新的0~4G的进程地址空间,而是使用当前进程的地址空间,但是该线程会创建出一个自己的PCB控制块

在这里插入图片描述
而一旦一个进程创建出一个线程,该进程也叫做线程了,就相当于从一开始的整租->合租,虽然你是第一个租的,但由于有别人一起来租,你们俩就都叫合租

所以,进程是最小的内存的资源分配单位,而进程是最小的执行单位,可以把进程看做是一个只有一个线程的进程

关于线程影响单核CPU分配资源:
在这里插入图片描述
起初,我们有三个进程,这三个进程一开始是平等的,他们会平均的争夺CPU,而此时,如果A进程新建两个线程,一共三个线程,此时CPU就会把更多的时间片分给进程A,因为最小执行单元是线程而不是进程,所以,在CPU眼里,进程A的三个线程就是三个进程,他将平均的时间分配给进程A的三个线程时,就意味着把更多的时间片分配给了进程A

但是不要向一个进程内塞过多的线程,这样反而到达一定的峰值之后,物极必反

如下图,firefox的例子:
在这里插入图片描述
我们开启一个firefox时,可以使用ps -Lf pid 来查看当前进程的线程状态,可以看到,启动一次火狐,他就开了45个线程(利用线程池的原理),其中LWP列的编号为线程号,可以看到,线程号是继续上面的进程号的,所以,在CPU眼里,线程是最小的执行单元

总结:
在这里插入图片描述

内核原理

图解

在这里插入图片描述
先看右边,当进程地址空间向物理内存映射时,他的数据段与物理内存并不是直接通过MMU去映射,而是先映射到PCB中的一个“描述虚拟地址空间”的指针,之后再映射到MMU,然后再映射到物理内存地址

而右图中圆圈圈起来的那一步:即从PCB到物理内存的具体映射,看左边所示:
PCB有一根指针,之后该指针指向一个页面,页面指向页表,页表指向页目录,页目录就会映射物理地址
而此时如果创建一个线程,那么该线程就会创建出一个PCB,指向同样的页面,所以,一个进程中的线程的地址空间是共享的

而这里区分新创建的一个进程:
在这里插入图片描述
如果创建一进程而不是线程,那么此时就会被分配一块独立的资源,此时该进程的三级页表与之前进程的三级页表完全不同

总结:
在这里插入图片描述

线程共享资源与非共享资源

共享资源

在这里插入图片描述
1、文件描述符表共享
2、信号的处理方式共享,但是不同线程之间的mask是不共享的,因此可以利用这一点进行指定哪个线程接收信号
5、共享内存地址空间,但是不共享栈区(因为线程就是寄存器和栈的集合,每个线程有每个线程独立的栈空间)

非共享资源

在这里插入图片描述
2、处理器线程和内核栈:其实就是寄存器的值和内核的一个栈区
3、用户空间栈也不共享
所以,不管是内核还是用户空间栈,都不共享

4、errno,起初,errno变量是一个全局变量,但是对于线程来说,errno是不共享的,但是对于其他全局变量是共享的
5、信号屏蔽字mask

线程优缺点

在这里插入图片描述
对于优点的第三点:数据通信方便、共享数据方便,主要是由于不同的线程是在同一块资源地址空间内的,所以,对于数据来讲,除了栈不共享,其他区域数据都共享(全局变量区、堆区、…)

总结:
在这里插入图片描述

线程控制原语

pthread_self、pthread_create

简介

在这里插入图片描述
在这里插入图片描述

代码

在这里插入图片描述
我们称main函数中的线程是主线程
而之后创建的线程是子线程

在主线程中,我们使用pthread_create创建子线程,参数:
参数一:传出参数,表示所创建的子线程的线程ID(注意不是lwp中的线程号)
参数二:传入参数,表示线程属性,通常传NULL,表示使用线程的默认属性
参数三:线程运行函数,该函数返回值必须为void *,参数是一个指针
参数四:表示线程运行函数的参数,由于是使用泛型指针,所以传参时可以传单参,也可以多参(通过结构体指针)

这里我们先传NULL

返回值:成功:0,失败:返回errno(直接返回errno,而不是设置errno)

在线程运行函数中,同样的,我们打印线程的pid和tid

注意:
1、打印tid时,要使用%lu控制符,因为pthread_t是unsigned long类型
2、编译时,要加上-pthread选项,或者加上-lpthread(前面加小L),这是链接线程库
3、main函数创建完子线程之后,不能立马退出,因为所创建的线程要依赖于主线程的内存资源,主线程若结束,子线程的内存资源也就没了,所以可以让主线程sleep,晚结束一会儿,等子线程打印完之后,再结束,而在实习时,使用的是while,保证主线程不结束
4、子线程函数规定返回值必须为void *,所以我们return NULL

总结

在这里插入图片描述

循环创建多个子线程

错误代码

在这里插入图片描述
在这里插入图片描述
可以看到thread的编号都变成了6

错误分析:
在这里插入图片描述
由于线程是不共享栈的,所以,上面的代码中,我们取i的地址,而i是main函数的局部变量,所以,我们将i的地址传给线程函数后,线程函数会拿到一个main中局部变量的地址,解引用且拷贝其值,但是在线程解引用拷贝值的时候,i 已经 ++了,因为main中的for循环是一个无需任何资源介入,执行很快的动作,而线程调用需要进出内核,所以,在线程解引用拷贝值的时候,i 已经 ++了,甚至++了很多次

修改:
在这里插入图片描述
直接将值,转为void *,之后在线程函数中,再转回int
在64位系统中,int是4字节,指针是8字节,我们先将一个4字节的值给到一个8字节的变量存储,之后,再从这个8字节的变量强转为4字节的变量中存储,只要进的时候不会缺失数据,出的时候也不会,所以,是可行的,但是编译器可能会给出警告,但是是可以运行的

效果:
在这里插入图片描述
如果想要消除警告:
在这里插入图片描述

总结:
在这里插入图片描述

线程间全局变量共享

在这里插入图片描述
首先,主线程打印一下var变量的初始值

之后,创建子线程,在子线程中对全局变量进行修改,并打印,之后,主线程停一秒,目的是等待子线程执行完毕,最后,在主线程中打印一下当前var的值

效果:
在这里插入图片描述

pthread_exit

简介

在这里插入图片描述
最后一句话说的是不要返回局部变量的地址

代码

需求:假如说,我们想要第三个线程退出,而其他线程继续工作

方式一:
在这里插入图片描述
使用exit(0),表示正常退出

效果:
在这里插入图片描述
第3个以及后面的线程没有输出,这是因为exit表示的是进程退出,整个进程被退出的话,所有的线程也会被退出

而exit之前,已经有两个线程输出,exit之后,所有线程退出,不再会有输出

方式二:
在这里插入图片描述
使用return

效果:
在这里插入图片描述
可以实现

方式三:
在这里插入图片描述
使用带有return NULL的一个函数,显然是不行的,因为return只返回当前函数,返回到上一级,上图return的功能只能影响到func函数,无法影响到tfn函数

效果:
在这里插入图片描述
修正:
在这里插入图片描述
但是如果所调用的函数中含有pthread_exit(),那么就可以影响到外层的线程,让线程退出,且仅退出线程,而不退出进程

效果:
在这里插入图片描述

当然我们直接将其放到线程函数才是最常规的:
在这里插入图片描述

补充:
在这里插入图片描述
现在来看我们之前的一个问题,就是主线程只创建一个子线程,但是,如果主线程不sleep,会在子线程执行打印之前,主线程return,将main函数返回给调用者,就会把进程结束,从而子线程无法打印内容

现在,我们将sleep(1)去除,同时将return改为pthread_exit((void *)0),这样,主线程退出不再使用进程退出,而是使用线程退出,那此时主线程退出就不会把进程退出,那么子线程也可以继续执行自己的内容了

*注意要将整数0转为void ,或者直接退出NULL也可

效果:
在这里插入图片描述
主线程和子线程都打印了自己的内容,当所有线程结束时,进程也就结束了

总结:
在这里插入图片描述

pthread_join(回收线程)

简介

在这里插入图片描述
功能对标进程的话就是回收线程,类似于wait

原型:
在这里插入图片描述
在这里插入图片描述
参数一:进程ID,注意这里不是指针,而是值(区别于pthread_create)
参数二:传出参数,表示退出状态,

返回值:成功:0,失败:返回错误号

对比记忆:
在这里插入图片描述
对于进程来说,其进程退出的返回值是int,那么要传出其退出状态,就要用int *
那么对于线程来说,其线程退出的返回值是void 星,那么要传出其退出状态,就要用void 星星

所谓退出状态,实际上就是接收return 返回的数据

代码

在这里插入图片描述
在子线程中,开辟堆区数据,之后对其赋值,然后返回给主线程的pthread_join,返回值可以使用return ,也可以使用pthread_exit

在这里插入图片描述
在主线程中,创建出来子线程之后,使用join阻塞等待回收子线程,并拿到子线程的返回值,主要通过参数二来拿到子线程的返回值,所以这里join的参数二是一个传出参数,要注意其类型要与返回值类型对应,更具体的说,参数二要传入子线程返回值类型的地址,并转为void **

最后返回值会传到retuval指针中,我们操作指针即可

补充:线程返回值是一个数
在这里插入图片描述
由于返回值直接将74转为了void * ,也就是直接将74存在了指针变量里,而join的参数二仍然要求是返回值的指针类型,即返回类型的基础上再加一个指针

但是最后打印的时候,要记得retval存放的就是74,而不是74的地址,所以,直接打印retval即可

补充:局部变量不可行:
在这里插入图片描述
当子线程想要返回一个自己函数内的局部变量时,肯定是不行的,因为一旦离开子线程,该变量就会被释放,数据就会无效

补充:局部变量可行:
在这里插入图片描述
而如果是主线程的局部变量将地址传入子线程函数,在子线程函数中处理完之后再返回出来,那么就可以拿到,这样是没问题的

pthread_cancel

简介

在这里插入图片描述

代码

在这里插入图片描述
子线程中,循环打印,表示自己还活着
在这里插入图片描述
主线程创建出来子线程之后,等待5秒,之后就调用pthread_cancel(tid),将子线程杀掉,这个就相当于进程中的kill

效果:
在这里插入图片描述

一级目录

二级目录

二级目录

二级目录

一级目录

二级目录

二级目录

二级目录

一级目录

二级目录

二级目录

二级目录

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

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

相关文章

传统CV算法——基于Sift算法实现特征点检测

图像尺度空间 在一定的范围内,无论物体是大还是小,人眼都可以分辨出来。然而,计算机要具备相同的能力却很难。因此,为了让机器能够对物体在不同尺度下有一个统一的认知,就需要考虑图像在不同尺度下所存在的特点。这就…

Infiniband网络架构的技术与性能分析

Infiniband格局寡头,性能占优 这篇文章探讨了网络交换机的性能优势,以及如何通过扩大模型参数量来提高语言模型的生成和预测能力。然而,计算约束对这种正向关系产生了重要影响,导致在相同的计算约束下,总存在最佳的模型…

Linux网络编程IO管理

网络 IO 涉及到两个系统对象,一个是用户空间调用 IO 的进程或者线程,一个是内核空间的内核系统,比如发生 IO 操作 read 时,它会经历两个阶段: 等待内核协议栈的数据准备就绪;将内核中的数据拷贝到用户态的…

随机森林Random Forest(RF)回归预测-MATLAB代码实现

一、随机森林RF(代码获取:底部公众号) 随机森林(Random Forest,RF)是一种机器学习方法,常用于回归预测和分类任务。它通过构建多个决策树,并通过组合它们的预测结果来进行回归预测。…

时序预测|基于粒子群优化支持向量机的时间序列预测Matlab程序PSO-SVM 单变量和多变量 含基础模型

时序预测|基于粒子群优化支持向量机的时间序列预测Matlab程序PSO-SVM 单变量和多变量 含基础模型 文章目录 一、基本原理1. 问题定义2. 数据准备3. SVM 模型构建4. 粒子群优化(PSO)5. 优化与模型训练6. 模型评估与预测7. 流程总结8. MATLAB 实现概述 二、…

浅谈人工智能之python调用通义千问API

浅谈人工智能之python调用通义千问API API-KEY建立 第一步:我们登录阿里云百炼 第二步:点击界面上查看我的API-KEY 第三步:在跳出来的界面中,点击创建API-KEY 第四步:在跳出来的界面中,在描述中输入“t…

算法——支持向量机(support vector machines,SVM)

简介:个人学习分享,如有错误,欢迎批评指正 支持向量机(Support Vector Machine, SVM)是一种监督学习算法,广泛用于分类任务,也可以用于回归和异常检测等问题。SVM的核心思想是通过在特征空间中找…

Unity【Colliders碰撞器】和【Rigibody刚体】的应用——小球反弹效果

目录 Collider 2D 定义: 类型: Rigidbody 2D 定义: 属性和行为: 运动控制: 碰撞检测: 结合使用 实用检测 延伸拓展 1、在Unity中优化Collider 2D和Rigidbody 2D的性能 2、Unity中Collider 2D…

2024/9/8周报

文章目录 摘要Abstract数据挖掘数据挖掘的目标数据挖掘的过程数据挖掘的技术应用领域工具与平台代码示例 总结 摘要 智慧水务项目中,需要对采集的总氮、氨氮、化学需氧量、硝态氮、总磷、硝态氮等数据进行数据处理与挖掘,因此本周对数据挖掘相关内容进行…

CommonCollections1

CommonCollections1 poc展示 这是一段POC,运行后会弹出一个计算器。 import org.apache.commons.collections.*; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; im…

C#使用MQTT(二):MQTT客户端

上一篇我们初步设计了MQTT服务端 C#使用MQTT(一):MQTT服务端-CSDN博客 这里我们设计客户端MQTT Client,接上一篇 新建Windows窗体FormMqttClient 窗体FormMqttClient设计如图: 窗体FormMqttClient设计器相关代码如下 文件FormMqttClient.Designer.cs namespace…

uni-app--》打造个性化壁纸预览应用平台(四)完结篇

🏙️作者简介:大家好,我是亦世凡华、渴望知识储备自己的一名前端工程师 🌄个人主页:亦世凡华、 🌆系列专栏:uni-app 🌇座右铭:人生亦可燃烧,亦可腐败&#xf…

论文写作神器!分享5款AI论文写作常用软件推荐

在当今学术研究和写作领域,AI论文写作工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿,还能进行内容优化、查重和排版等操作。以下是五款目前最好用的AI论文写作软件推荐: 1. 千笔-AIPassPaper 千笔-…

SpringCache之本地缓存

针对不同的缓存技术,需要实现不同的cacheManager,Spring定义了如下的cacheManger实现。 CacheManger 描述 SimpleCacheManager 使用简单的Collection来存储缓存,主要用于测试 ConcurrentMapCacheManager 使用ConcurrentMap作为缓存技术&…

mac 安装redis

官网下载指定版本的redis https://redis.io/ 目前3.2.0 是最新最稳定的 版本 这里是历史版本下载 下载指定版本 安装 1.放到自定义目录下并解压 2.打开终端,执行命令 cd redis的安装目录下 make test -- 此命令的作用是将redis源代码编译成可执行文件&#xff0c…

java基础概念21-权限修饰符、代码块

一、权限修饰符 1-1、作用 权限修饰符,是用来控制一个成员能够被访问的范围的。 可以修饰:成员变量,方法,构造方法,内部类。 1-2、权限修饰符的分类 二、代码块 局部代码块构造代码块静态代码块 2-1、局部代码块 …

day1 QT

作业 #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//设置窗口大小this->resize(1025,533);//固定窗口大小this->setFixedSize(1025,533);//设置窗口背景色,设置弧度//this->setStyleSheet("background-image:url(E:/…

肖扬老师好书《微权力下的项目管理(第3版)》读书笔记1

肖扬老师好书《微权力下的项目管理(第3版)》,的确不错,分别共读之。 第2章 精华 为了在项目过程中成为一名优秀的导演,项目经理要同时修炼领导和管理这两种不同的能 力,因为项目管理模式就是一种游走于领导…

计算机网络知识点复习——TCP协议的三次握手与四次挥手(连接与释放)

TCP协议的三次握手与四次挥手(连接与释放) 一、前言二、简单的知识准备1. TCP协议的主要特点2. TCP报文段 三、TCP连接的建立(三次握手)四、TCP连接的释放(四次挥手)五、TCP连接与释放的总结六、结束语 一、…

MySQL record 01 part

更改密码: alter user rootlocalhost identified with mysql_native_password by ‘123456’; 注意: 在命令行方式下,每条MySQL的命令都是以分号结尾的,如果不加分号,MySQL会继续等待用户输入命令,直到MyS…