系统编程--线程

线程概念

什么是线程

简介

在这里插入图片描述

图解

在这里插入图片描述
对于一个进程来说,他有独立的进程地址空间,如上图左侧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

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

一级目录

二级目录

二级目录

二级目录

一级目录

二级目录

二级目录

二级目录

一级目录

二级目录

二级目录

二级目录

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值