-
目录
-
线程同步之互斥量
- 回顾下之前的模型:
- 有2个线程,分别为线程1,2;
- 分别充当了生产者和消费者的角色
- 同时操作1个临界资源
- 互斥量在其中作用:
- 如某个线程在操作临界资源时,它就能阻止另外一个线程去访问这个临界资源
- 两个线程的指令交叉执行就引发了线程同步的问题
- 而互斥量可以保证先后顺序执行
- 这种效果也称之为原子性,互斥量就是保证了这些关键指令的原子性
- 原子性是指一系列操作不可被中断的特性
- 这一系列操作要么全部执行完成,要么全部没有执行
- 不存在部分执行部分未执行的情况
- 互斥量是最简单的线程同步的方法
- 也称为互斥锁,它是处于两态之一的变量:解锁和加锁
- 要么处于解锁的状态,要么处于加锁的状态
- 这两个状态可以保证资源访问的串行
- 操作系统直接提供了互斥量的API
- 开发者可以直接使用API完成资源的加锁、解锁操作
-
线程同步之自旋锁
- 也是在使用临界资源加一个锁,完成后释放掉,以保证串行访问
- 自旋锁也是一种多线程同步的变量
- 使用自旋锁的线程会反复检查锁变量是否可用,如果不可用,将会一直循环反复去检查,直到获取到锁才会退出循环
- 自旋锁不会让出CPU,获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,是一种忙等待状态
- 就是死循环等待锁被释放的一种锁
- 自旋锁与互斥锁比较类似,都是为了解决对某项资源的互斥使用
- 无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个持有者,即只能有一个执行单元获得锁
- 但是两者在调度机制上略有不同
- 对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态
- 但是自旋锁不会引起调用者睡眠,而是一直循环在那里看是否该自旋锁的持有者已经释放了锁,"自旋"一词就是因此而得名。锁一旦被释放,就会被等待的线程立即获取,而不需要经过唤醒和上下文切换
- 不需要进行上下文切换和任务调度
- 自旋锁避免了进程或线程上下文切换的开销
- 操作系统内部很多地方使用的是自旋锁
- 自旋锁不适合在单核CPU使用
- 自旋锁是专为防止多处理器并发而引入的一种锁,它在内核中大量应用于中断处理等部分(对于单处理器来说,防止中断处理中的并发可简单采用关闭中断的方式,即在标志寄存器中关闭/打开中断标志位,不需要自旋锁)
- 它在运行时不会让出CPU,这就是与互斥量最大的区别
- 适用情况:
- 自旋锁是一种比较低级的资源保护方式比较适用于保护访问耗时较短的资源
- 信号量和互斥锁适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在线程上下文使用;
- 而自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用
-
线程同步之读写锁
- 为何有读写锁
- 在复杂的开发环境中,临界资源很可能出现多读少写的特性
- 例:一个数据库存储历史订单,一般都是查询,很少去更改这些订单信息,这就属于多读少写的临界资源
- 而读取时并不会改变临界资源的值;每一次去读或写时都给它加锁,效率是很低的
- 基于这个考量,可以得出一种效率更高的同步方法,即读写锁
- 读写锁是一种特殊的自旋锁
- 允许多个读者同时访问资源以提高读性能
- 由于写会改变临界资源的值,所以对于写操作则是互斥的
-
线程同步之条件变量
- 条件变量是一种相对复杂的线程同步方法
- 条件变量允许线程睡眠,直到满足某种条件
- 当满足条件时,可以向该线程发出信号,通知唤醒
- 以生产者消费者模式来看:
- 缓冲区小于等于0时,不允许消费者消费,消费者必须等待
- 当生产者生产一个产品时,唤醒可能等待的消费者
- 缓冲区满时,不允许生产者往缓冲区生产,生产者必须等待
- 当消费者消费一个产品时,唤醒可能等待的生产者
- 这2种唤醒操作正是通过条件变量所实现的
- 条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用
- 条件变量之所以要和互斥锁一起使用,主要是因为互斥锁的一个明显的特点就是它只有两种状态:锁定和非锁定,而条件变量可以通过允许线程阻塞和等待另一个线程发送信号来弥补互斥锁的不足,所以互斥锁和条件变量通常一起使用
- 两个线程利用条件变量及互斥锁实现同步
- 一个线程利用条件变量实现等待,同时释放锁;
- 一个线程获取锁后利用该条件变量唤醒等待的线程
操作系统之提升篇-(1)线程同步
猜你喜欢
转载自blog.csdn.net/weixin_59624686/article/details/125074687
今日推荐
周排行