清华大学《操作系统》(十二):临界区与锁

多进程并发运行,导致多个进程间有资源共享,比如CPU、内存,因此存在不确定性和不可重现,可能导致多次运行结果不一致。因此操作系统需要利用同步机制在并发执行的同时,保证一些操作是原子操作。

  • 互斥是指一个进程占用了某个资源,其他进程都不能使用该资源;
  • 死锁是指多个进程各占有了一部分资源,形成了循环等待;
  • 饥饿是指其他进程轮流占用资源,一个进程一直得不到资源。

临界区

为解决进程间同步导致的这些问题,提出了一些方案。临界区是指进程中访问临界资源的一段需要互斥执行的代码。进入临界区之前需要判断能否进入,进入时需要改变标志阻止其他进程进入,进入的进程执行完成后退出时修改标志。

临界区访问规则:

  • 空闲则入,没有进程进入时可以进城;
  • 忙则等待,有进程在临界区时其他进程均不可进入;
  • 有限等待,等待进入临界区的进程不能无限制等待;
  • 让权等待,不能进入的进程应释放CPU进入阻塞状态。

临界区实现方式:

  • 禁用中断,进入临界区后不响应中端;
  • 软件方式,共享变量协调;
  • 借用操作系统提供高级的抽象方法。

显然第三种方式是可取的,其他两种都有明显的缺陷。下面对第三种方式进行介绍。

方法一:禁用中断

缺点:

  • 禁用中断后,进程无法被停止。整个系统都会为此停下来,可能导致其他进程处于饥饿状态
  • 临界区可能很长,无法确定响应中断所需的时间(可能存在硬件影响)

方法二:软件中断

       

缺点:

  • 需要两个进程间的共享数据项
  • 需要忙等待,浪费CPU时间

方法三:原子操作指令

更高级的抽象方法实际是借助硬件的同步原语来实现的。

  • 硬件提供了一些同步原语,包括中断禁用、原子操作指令等,从硬件上保证多个操作的原子性。
  • 操作系统提供更高级的编程抽象来简化进程同,。实现方式有锁、信号量。

锁是一个抽象的数据结构,由一个二进制变量(锁定/解锁)和两个操作原语(锁的请求和锁的释放)组成。二进制变量用于标志锁的状态,锁的请求使锁在被释放前一直等待,并且使进程得到锁,这两者是原子的,释放锁时唤醒其他等待锁的进程。

内部基于CPU体系结构提供的一些特殊的原子操作指令,这些指令把若干个指令合并为一次原子操作,保证不会出现部分执行的状态。这些原子操作指令包括测试和置位指令(Test-and-Set,即TS指令,返回内存地址中的值,并将其置为1)、交换指令(交换内存中的两个值)。

基于TS指令可以实现如下图所示的自旋锁,自旋锁的缺点是线程等待时消耗CPU时间。

      

针对自旋锁的问题,出现了无忙等待锁,当锁已经被占用时,将自身线程放入等待队列,并调用调度程序。当其他线程释放锁时会将所有等待中的线程重新唤醒。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值