问题
如何设置获取互斥量时的等待时间?
如果等待超时,如何避免死锁?
避免死锁 -- 设置等待超时
解决方案:
1、尝试获取第 1 个互斥量:
- 若成功,则转 2 执行;若失败,则等待;
2、尝试在规定时间内获取第 2 个互斥量:
- 若成功,则执行临界区代码
- 若失败,则释放第 1 个互斥量,休眠后转 1 执行
互斥量获取超时 API 函数
"活锁" 解决方案实现
思考
线程获取互斥量失败后究竟发生了什么?
Linux 中的自旋锁
自旋锁也是一种用于保证临界区的原子性的机制
自旋锁与互斥量类似,在任何时刻,最多只能有一个持有者
自旋锁与互斥量在内部机制上不同:
- 互斥量:
- 如果已经被其他线程持有,则当前线程进入等待状态 (不占用处理器,进入等待队列)
- 自旋锁:
- 如果已经被其他线程持有,则当前线程一直循环查看自旋锁是否再次可持有
互斥量 vs 自旋锁
应用场景
- 互斥量是一种普适的解决方案,通用性强,副作用小
- 自旋锁是一种特定场景下的解决方案,通用性弱,副作用大
实现机制
- 互斥量涉及线程上下文切换,因此在效率上存在不足 (消耗时间资源)
- 线程一直尝试获取自旋锁,因此不会进入阻塞状态 (消耗处理器资源)
Linux 中的自旋锁 API 函数
自旋锁类型:
- PTHREAD_PROCESS_PRIVATE => 进程内自旋锁 (同一进程中的线程可用)
- PTHREAD_PROCESS_SHARED => 进程间自旋锁 (任意进程的任意线程可用)
下面的多线程程序有问题吗?
自旋锁使用细则
轻量级锁定,即:临界区相对短小,自旋锁持有时间非常短
同一线程不可重复获取自旋锁 (导致死锁)
如果只有一个单核处理器,不建议使用自旋锁
线程一旦获取自旋锁,则不能让出处理器使用权
即:线程 获取锁 到 释放锁 的时间内只有一个执行流
有没有一种可能
存在一种 "锁" 类型:
- 效率高 => 不会轻易发生上下文切换,使得线程进入阻塞状态
- 无死锁 => 不会无限制自旋,适合的时间让出处理器使用权
关于 PTHREAD_MUTEX_ADAPTIVE_NP 类型
一种特殊的互斥量,又名:自适应锁
自适应锁先以自旋的方式持续尝试获取目标锁
当超时未能获取目标锁,则让出处理器使用权,线程进入阻塞状态
自适应锁相对普通互斥量效率更高,相对自旋锁安全性更好