在java中我们知道对线程使用CAS(compare and swap)来实现自旋锁,在没有学习操作系统之前,我以为这是唯一一种方法了。但是今天学到了操作系统中的同步互斥,终于明白了原来CAS、TS、Swap这些都是硬件提供的原子操作罢了!不仅CAS可以实现自旋锁,TS(Test and Set)同样可以!
临界区
- 临界区
进程中访问临界资源的一段需要互斥执行的代码
进入区
- 检查可否进入临界区的一段代码
- 如可进入,设置相应“正在访问临界区”标志
退出区
- 清楚“正在访问临界区”标志
剩余区
- 代码的剩余部分
临界区的访问规则
- 空闲则入
- 没有进程在临界区时,任何进程可进入
- 忙则等待
- 有进程在临界区时,其他进程均不能进入临界区
- 有限等待
- 等待进入临界区的进程不能无限期等待
- 让权等待(可选)
- 不能进入临界区的进程,应释放CPU(如转换到阻塞状态)
临界区的实现方法
- 禁用中断
- 软件方法
- 更高级的抽象方法
方法3:高级抽象的同步方法
- 硬件提供了一些同步原语
- 中断禁用,原子操作指令
- 操作系统提供更高级的变成抽象来简化进程同步
- 例如:锁、信号量
- 用硬件原语来构建
锁lock
- 锁是一个抽象的数据结构
- 一个二进制变量(锁定/解锁)
- Lock::Acquire()
- 锁被释放前一直等待,然后得到锁
- Lock::Release()
- 释放锁,唤醒任何等待的进程
原子操作指令
现代CPU体系结构都提供了一些特殊的原子操作指令
测试和置位(Test-and-set)指令
- 从内存单元中读取值
- 测试该值是否为1(然后返回真或假)
- 内存单元值设置为1
使用TS指令实现自旋锁
class Lock{
int value = 0;
}
Lock::Acquire() {
while( test-and-set(value))
; //spin
}
Lock::Release() {
value = 0;
}
如果锁被释放,那么TS指令读取0并将值设置为1
- 锁被设置为忙并且需要等待完成
如果锁处于忙状态,那么TS指令读取1并将值设置为1
- 不改变锁的状态并且需要循环
它的问题是线程在等待的时候也要消耗CPU的时间
很多原子操作指令都可以做到同步互斥中用户态难以做到的事情。
Hello World社区的界面很美观~希望可以和Hello World一起成长