线程

线程

在传统操作系统中,进程就是一个运行程序的描述信息PCB——进程控制块,控制程序的运行
但LINUX下没有真正的线程,因为linux下的线程是用进程PCB模拟的,所以LINUX下的线程也叫轻量级进程,所以此时进程也叫线程组,包含一个或多个线程
linux下并没有为线程设计一个tcb来控制线程的运行

pid(线程ID)
tgid(进程ID)——进程组ID,第一个线程的ID

因为CPU调度程序运行是调度PCB,而LINUX下的PCB是线程,因此线程是CPU调动的基本单位
因为在执行一个程序的时候会分配大量的资源给线程组,所以进程是操作系统资源分配的基本单位,这些资源是分配给线程组中的所有线程(因为他们共用这些资源),资源是以进程分配的,进程中的所有线程共用

vfork 因为创建子进程与父进程共用一个虚拟地址空间,因此不能同时运行
同一个进程的线程之间独有的数据
1.栈
2.寄存器
3.errno
4.信号屏蔽字
5.线程标示符

同一个进程的线程之间共享数据:
1.数据段 代码段
2.文件描述符表
3.信号的处理方式
4.工作路径
5.用户id,组id

多线程和多进程都可以并发完成任务,哪个好?
多线程优点:1.共享同一个虚拟地址空间 线程间通信特别方便
2.线程的创建/销毁成本更低
3.同一个进程间的线程的调度成本更低
4.执行粒度更加细致
缺点:缺乏访问控制 健壮性低 一些系统调用和异常 某些系统调用针对整个进程产生效果
共同优点:都可以并行或者并发处理任务,提高效率
CPU密集程序:程序中大量的运算操作
IO密集程序:程序中大量的IO操作
共同缺点:对临界资源操作需要考虑更多,编码更加复杂

多进程场景:对主进程安全度要求特别高的程序——比如shell (让子进程完成程序更加安全,稳定)

线程和进程:
线程是CPU调度基本单位,进程是资源的分配基本单位
linux下的线程共用进程的虚拟地址空间
线程的创建/销毁成本更低
线程的调度切换要更加低
线程间的通信更加方便
线程间的执行力度更加细致
缺点:缺乏访问控制——线程安全
有些系统调用和程序异常是针对整个进程产生影响的
多个线程对临界资源进程操作会造成数据混乱
即便如此——线程依然是每个项目中都会用到的

多线程/多进程
多进程任务处理:将多个任务分解成多个任务(分解到多个进程中完成) 多个虚拟地址 多个PCB
多线程任务处理:多个pcb共同用一个虚拟地址空间,同时完成一个代码中多个不同模块的功能
线程概念:
线程控制:线程创建 线程终止 线程等待 线程分离
线程安全:概念,如何实现,同步,互斥
IO密集型程序——分摊等待
cpu密集型程序——分摊计算
线程共享:
文件状态表 用户ID组ID
信号处理方式 当前工作目录
线程独有:(相对独有——因为独有的数据还是在虚拟地址空间中 )
栈区,上下文数据,线程Id,error,信号屏蔽字

线程控制:线程创建 线程终止 线程等待 线程分离 pthread_
操作系统并没有提供相对应的系统调用来实现线程的接口,所以有大佬们就为线程的控制封装了一套线程库,使用这套接口创建的线程称之为用户态的线程,但是它在操作系统的内部对应了一个轻量级进程
线程创建:

 int pthread_create(pthread_t *thread,pthread_attr_t *attr, void *(*start_routine)(void *),void *   arg);

thread:用于获取线程ID(用户态的线程ID)
attr:设置线程属性,通常设置NULL
start_routine:线程入口函数,线程所运行的代码
arg:线程入口函数的参数
返回值: 成功:0  失败:非0

通过参数返回一个用户态的线程ID——是线程地址空间在进程虚拟地址空间中的首地址,这个用户态线程的操作都是围绕这个用户态的线程ID来操作的
pthread_self这个接口用于回去线程自身的ID
每一个线程都是一个task_struct也就意味着每个线程都有一个pid,但是ps命令只能显示一个,task_struct中不仅有pid还有一个tgid(线程组ID==线程组领导者的pid),那么ps看到的pid实际上是这个tgid(线程组ID),因此我们所linux下的进程成为了线程组
查看线程信息可以使用ps -L命令 LWP这一列显示的就是线程pcb中的pid
LWP:task_struct->pid
PID:task_struct->tgid (线程组id) 默认等于线程组中主线程pid
tid:首地址(共享区中线程地址空间的首地址)

线程终止
线程入口函数中return ,不能在main中return,不能调用exit,因为这两个都是退出进程的,进程退出了,所有的线程都得退出

pthread_exit(void *retval): 线程退出
retval :线程的退出返回值     谁调用谁退出   退出自己
线程退出也会形成僵尸进程,因为线程退出也要保存自己的脱出返回值

pthread_cancel(pthread_t   thread):    取消指定的线程   
thread :线程ID    

线程等待
获取指定的
功能: 等待进程退出,获取返回值,回收线程资源
前提:这个被等待的线程必须处于joinable状态

线程分离
int pthread_detach(pthread_t thread);
功能 分离一个线程(设置线程的属性从joinable->detach属性)

线程安全:多个线程同时操作临界资源而不会出现数据二义性
在线程中是否对临界资源进行了非原子操作
可重入/不可重入:多个执行流程中是否可以同时进入函数运行而不会出现问题
如何实现线程安全
同步:临界资源访问时的时序可控
互斥:临界资源同一时间唯一访问

互斥如何实现:互斥锁
互斥锁:如何实现安全操作 1/0计数器原子操作
一个0/1的计数器 1表示可以加锁,加锁就是计数-1;操作完毕之后要解锁,解锁就是计数+1;0表示不可加锁,不能加锁则等待

互斥锁操作步骤
1.定义互斥变量 pthread_mutex_t
2.初始化互斥锁变量 pthread_mutex_init
3.加锁 pthread_mutex_lock
4.解锁 pthread_mutex_unlock
4.销毁互斥锁 pthread_mutex_destroy

死锁:因为加锁之后没有解锁导致程序卡死的情况

死锁产生的四个必要条件
1.互斥条件(我操作的时候别人不能操作)
2.不可剥夺条件(我的锁,别人不能释放)
3.请求保持条件(拿着手里的,请求其他的,其他的请求不到,手里的也不放)
4.环路等待条件

产生场景:加锁/解锁顺序不同
预防死锁:破坏必要条件
避免死锁:死锁检测算法,银行家算法

同步的实现:临界资源的合理性 ——生产出来才能使用 等待+唤醒gg
没有资源则等待(死等),产生资源后唤醒+等待
条件变量:
1.定义条件变量 pthread_cond_t
2.初始化条件变量 pthread_con d_init
3.等待/唤醒 pthread_cond_wait/signal
4.销毁条件变量 pthread_cond_destroy
生产者和消费者模型: pthread_cond_

条件变量本身只提供等待与唤醒功能,具体什么时候等待需要用户来判断,这个条件的判断,通常涉及临界资源的操作(其他线程要通过修饰条件,来促使条件满足),而这个临界资源的操作应该受到保护,因此搭配互斥锁一起使用

线程有多少种角色,就应该有多少个变量,分别等待,分别唤醒

生产者与消费者模型:
功能解析:解耦 / 支持忙闲不均 / 支持并发
一个场所两类角色三种关系 (场所:线程安全的队列 两个角色:生产者消费者,都是线程 )
场所指的是数据的存放位置
角色指的是生产者和消费者
三种关系指的是如何保证数据的安全访问
生产者和生产者之间的关系是互斥关系
消费者与消费者之间的关系是互斥关系
生产者和消费者之间的关系是同步+互斥关系

信号量与条件变量的区别:
信号量拥有资源计数的功能,临界资源是否能够操作通过自身计数判断
条件变量是搭配互斥锁一起使用的
信号量可以实现互斥,计数仅0/1

posix信号量:
信号量的本质,就是一个计数器(标注是否具有资源可以操作)( 一个具有等待队列的计数器)
功能:实现进程/线程间的同步、互斥
接口:sem_init sem_destroy sem_wait sem_post

定义:sem_t 信号量变量
初始化:sem_init
数据操作前资源计数判断:sem_wait
计数>0则计数-1 直接返回。往下操作
计数<=0 则计数-1 阻塞等待
生产数据后则计数+1 唤醒等待:sem_post
销毁:sem_destroy

销毁:

读写锁(计数标记+自旋锁):实现写互斥,读共享;应用于少写 多读 耗时短的场景
pthread_rwlock_init pthread_rwlock_destroy pthread_rwlock_rdlock pthread_rwlock_wrlock
pthread_rwlock_unlock
默认读优先如果要写优先 需设置读写锁属性
pthread_rwlockattr_setkind_np
PTHREAD_RWLOCK_PREFER_NONRECURSIVE_NP

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值