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接口封装
对 用户 提供进行线程控制的接口
在创建makefile时,是需要将加入 pthread 库的,使操作系统对接口进行封装,使用户可以识别到线程
2. pthread_create —— 线程创建
输入 man pthread_create
第一个参数 为 线程id
第二个参数为 线程的属性 一般设为nullptr
第三个参数为 函数指针
新线程会执行新的方法,主线程会继续向后执行,两个执行流会各自执行各自的
第四个参数 ,当要回调方法时 arg作为函数指针传递的参数
进程创建成功为0,失败为错误码
让多个线程执行同一个函数 thread_run
使用snprintf,将字符串"thread -i"传入 tname中
调用 pthread_create时,将tname传过去作为 自定义函数 thread_run 的参数
再通过name将字符串"thread -i" 在线程中打印出来
当创建出来一个线程时,该线程对应的tname缓冲区属于多个线程共享的
传递的参数并非缓冲区本身,而是缓冲区的起始地址
当在自定义函数中 通过name拿到缓冲区的起始地址
主线程创建新线程之后,主线程会继续运行时,重新对缓冲区的内容进行覆盖
覆盖后,并没有改变在上一个线程传递的起始地址,即name没有变化,但是内容为缓冲区更新后的
将空间开辟在堆上,即可解决这个问题
运行可执行程序后,每个线程都有对应的数字存在
循环多少次,new就会执行多少次,随着每一次的new,传递给新线程的起始地址就只属于该线程
3. pthread_join —— 线程等待
输入 man pthread_join
第一个参数为 线程id
第二个参数为 是一个输出型参数 可以拿到新线程的退出结果
成功返回0,失败返回错误码
等待方式默认是阻塞的,若新线程没有退出, 主线程就一直等待,直到新线程退出
运行可执行程序,虽然主线程没有写死循环,但是程序会一直循环跑下去
主线程并不会退出,因为它要等待新线程退出
3. 线程终止
1. 线程函数执行完毕
在自定义函数中,使用return 退出
运行可执行程序后,出现 all thread quit 代表 线程全部退出了
2. pthread_exit
输入 man pthread_exit
参数类型为void*
自定义函数的返回类型为void*,所以可以把自定义函数的返回值拿回来
通过 pthread_exit 将新线程的退出信息返回
新创建一个ret的指针变量,虽然是void*类型,但是也会开辟空间
是由 pthread_join 的第二个参数 ret去接收返回值的
由于1是int类型,而自定义函数是void*类型,所以需要强转
再把强转后的1 传给了 ret,再通过强转把1打印出来
每个线程都打印出 thread quit : 1
4. pthread_cancel——线程取消
输入 man pthread_cancel
参数为 线程id
在休眠3秒后,当前线程被取消
新线程有5秒的数据,但是只执行了3秒,主线程 取消了新线程
5. pthread_self——获取线程id
输入 man pthread_self
运行可执行程序后,发现在主函数中直接使用对应 线程求的值与自定义函数调用pthread_self 对应值 是相同的,
说明 pthread_self 就是用来获取线程的id