【Linux】线程控制

简介: 【Linux】线程控制

1. 进程 VS 线程

1. 进程和线程

1.进程是资源分配的基本单位

2.线程是调度的基本单位

3.线程共享进程数据,但也拥有自己的一部分数据

线程id (LWP)


一组寄存器

(当前线程所对应执行的上下文数据) 因为多线程是要被切换,所以它的上下文数据为私有的,不能和其他发生冲突


每一个线程都有自己独立的栈结构

若每一个线程都有一个临时变量,则将所有的临时变量数据都放入地址空间的栈中,就会导致数据谁是谁的分不清楚

所以线程在处理临时数据时就要有自己独立的栈


errno (错误码)

信号屏蔽字

调度优先级

2.进程的多个线程共享

同一地址空间中,代码区 ,数据区都是共享的,

若定义一个函数,在各线程都可以调用

定义一个全局变量,在各线程处都可以访问到

各线程还共享如下的进程资源和环境:

1.文件描述符表

主线程打开一个文件,然后又创建了一个新线程,新线程可以看到主线程打开的文件,同样也可以读取文件描述符


不懂查看:文件描述符本质理解


2.每种信号的处理方式

SIG_IGN SIG_DFL 自定义处理信号处理函数

3.当前工作目录

4.用户id 和组id

2. 线程控制

1.为什么使用线程要调用库?

操作系统视角:Linux下们没有真正意义的线程,而是用进程模拟的线程(LWP),Linux 不会提供直接创建线程的系统调用,最多提供创建轻量级进程的接口


用户视角:用户只认线程


用户和操作系统之间需要 库 , 被称为 用户级线程库 (pthread), 任何系统都需要自带,即原生线程库

对操作系统 将Linux接口封装

对 用户 提供进行线程控制的接口


50d9b1426be74892b2a42f7590becfc6.png


在创建makefile时,是需要将加入 pthread 库的,使操作系统对接口进行封装,使用户可以识别到线程

2. pthread_create —— 线程创建

输入 man pthread_create

19cb53eff72549518528011a9acb10a8.png

第一个参数 为 线程id

第二个参数为 线程的属性 一般设为nullptr

第三个参数为 函数指针

新线程会执行新的方法,主线程会继续向后执行,两个执行流会各自执行各自的

第四个参数 ,当要回调方法时 arg作为函数指针传递的参数

进程创建成功为0,失败为错误码

bb85b0bae240422e97d9aebf46bf0c7e.png

让多个线程执行同一个函数 thread_run

使用snprintf,将字符串"thread -i"传入 tname中

调用 pthread_create时,将tname传过去作为 自定义函数 thread_run 的参数

再通过name将字符串"thread -i" 在线程中打印出来


7091d3213d9041fbb60e8fa3b27b9382.png

当创建出来一个线程时,该线程对应的tname缓冲区属于多个线程共享的

传递的参数并非缓冲区本身,而是缓冲区的起始地址


当在自定义函数中 通过name拿到缓冲区的起始地址

主线程创建新线程之后,主线程会继续运行时,重新对缓冲区的内容进行覆盖

覆盖后,并没有改变在上一个线程传递的起始地址,即name没有变化,但是内容为缓冲区更新后的

97054ecd8f594cf0b414473555618b81.png


将空间开辟在堆上,即可解决这个问题


78a590114f4946d18caa9a0f05364f02.png


运行可执行程序后,每个线程都有对应的数字存在

循环多少次,new就会执行多少次,随着每一次的new,传递给新线程的起始地址就只属于该线程


3. pthread_join —— 线程等待


输入 man pthread_join


791855d05ceb4fd28d797ddc6e2d296c.png


第一个参数为 线程id

第二个参数为 是一个输出型参数 可以拿到新线程的退出结果

成功返回0,失败返回错误码


等待方式默认是阻塞的,若新ccf47eee0d8844b99d8d17be0d2700f2.png线程没有退出, 主线程就一直等待,直到新线程退出


dbadb206915441489041553279576d3a.png


运行可执行程序,虽然主线程没有写死循环,但是程序会一直循环跑下去

主线程并不会退出,因为它要等待新线程退出


3. 线程终止

1. 线程函数执行完毕

60430787d5bc4ce8969652307e5980ba.png

在自定义函数中,使用return 退出


f72c816f3a2a43419f704af84f25bb60.png

7499f6010433421d876a9fe944a67344.png

运行可执行程序后,出现 all thread quit 代表 线程全部退出了

2. pthread_exit


输入 man pthread_exit

1f04c44809494f988566574de51dc476.png

参数类型为void*

自定义函数的返回类型为void*,所以可以把自定义函数的返回值拿回来

e8f18b42668c41dbbbd9751ecdb46760.png

通过 pthread_exit 将新线程的退出信息返回

新创建一个ret的指针变量,虽然是void*类型,但是也会开辟空间

是由 pthread_join 的第二个参数 ret去接收返回值的

2b22d0c71d954866aed85ef98cff16a1.png

由于1是int类型,而自定义函数是void*类型,所以需要强转

再把强转后的1 传给了 ret,再通过强转把1打印出来

81d4f495399e426486929ff110c5ded0.png

每个线程都打印出 thread quit : 1

4. pthread_cancel——线程取消

输入 man pthread_cancel


4ea6cb9a3bb0426baad786b508cb8ecf.png

参数为 线程id


f9ca16df9da946839845fe20a547b8ec.png

在休眠3秒后,当前线程被取消


a24e3b09a50a4e178044544c2ef6a828.png

新线程有5秒的数据,但是只执行了3秒,主线程 取消了新线程


5. pthread_self——获取线程id

输入 man pthread_self


f3dab7bdbe86417481066a372448ce45.png

62862d752a8c4c18ae7049e2ef97ef6b.png

1a4d620b465b4b78bb26bdd7a7c6c4ee.png

运行可执行程序后,发现在主函数中直接使用对应 线程求的值与自定义函数调用pthread_self 对应值 是相同的,

说明 pthread_self 就是用来获取线程的id


相关文章
|
3月前
|
算法 Unix Linux
linux线程调度策略
linux线程调度策略
77 0
|
1月前
|
资源调度 Linux 调度
Linux C/C++之线程基础
这篇文章详细介绍了Linux下C/C++线程的基本概念、创建和管理线程的方法,以及线程同步的各种机制,并通过实例代码展示了线程同步技术的应用。
29 0
Linux C/C++之线程基础
|
1月前
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解
|
3月前
|
存储 设计模式 NoSQL
Linux线程详解
Linux线程详解
|
3月前
|
缓存 Linux C语言
Linux线程是如何创建的
【8月更文挑战第5天】线程不是一个完全由内核实现的机制,它是由内核态和用户态合作完成的。
|
3月前
|
负载均衡 Linux 调度
在Linux中,进程和线程有何作用?
在Linux中,进程和线程有何作用?
|
3月前
|
缓存 Linux C语言
Linux中线程是如何创建的
【8月更文挑战第15天】线程并非纯内核机制,由内核态与用户态共同实现。
|
5月前
|
API
linux---线程互斥锁总结及代码实现
linux---线程互斥锁总结及代码实现
|
5月前
|
Linux API
Linux线程总结---线程的创建、退出、取消、回收、分离属性
Linux线程总结---线程的创建、退出、取消、回收、分离属性
|
5月前
|
API
Linux---线程读写锁详解及代码实现
Linux---线程读写锁详解及代码实现