操作系统笔记——第9章 同步

背景

合作的线程:线程之间对共享资源协同合作,进程/线程、计算机/设备需要合作。

  • 共享资源
  • 加速:I/O操作和计算可以重叠;多处理器-将程序分为多个部分并行执行
  • 模块化:将大程序分解成小程序;使系统易于扩展

程序可以调用函数fork()创建一个新进程

  • 操作系统需要分配一个新的且唯一的进程ID
  • 在内核中,这个系统调用会运行 new_pid = next_pid++
  • 翻译成机器指令(4条)
    • LOAD next_pid Reg1
    • STORE Reg1 new_pid
    • INC Reg1
    • STORE Reg1 next_pid
  • 假设两个进程并发执行
    • 进行上下文切换之后可能会出现多种bug

同步互斥产生的背景

  • 无论多个线程的指令序列怎样交替自行,程序都必须正常工作
    • 多线程程序具有不确定性和不可重现的特点
    • 不经过专门设计,调试难度很大
  • 不确定性要求并行程序的正确性

一些概念

Race Condition(竞态条件)

  • 系统缺陷:结果依赖于并发执行或事件的顺序/时间
    • 不确定性
    • 不可重现

Atomic Operation(原子操作)

  • 原子操作指一次不存在任何中断或失败的执行
    • 该执行成功结束;或者根本没有执行
    • 并且不应该发现任何部分的执行状态
  • 实际上操作系统的操作往往不是原子的

实现原子操作的思路

  • Lock(锁)
  • 保护装置
  • Unlock(解锁)
    • 打开保护性装置
  • 问题:Deadlock(死锁)
    • A拿到锁1,B拿到锁2,A想继续拿到锁2再继续执行,B想拿到锁1再继续执行,导致A和B都不能继续执行。

Dead lock(死锁)

  • 两个及以上的进程,在相互等待完成特定任务,而最终没法将自身任务执行下去

Starvation(饥饿)

  • 一个可执行的进程,被调度器持续忽略,以至于虽然处于可执行状态却不被执行

Critical section(临界区)

  • 临界区是指进程中的一段需要访问共享资源并且当另一个进程处于相应代码区域时便不会被执行的代码区域
  • 属性
    • progress:如果一个线程想要进入临界区,那么它最终会成功
    • 有限等待:如果一个线程i处于入口区,那么在i的请求被接受之前,其他线程进入临界区的时间是有限制的(避免饥饿)
    • 无忙等待(可选):如果一个进程在等待进入临界区,那么在它可以进入之前会被挂起(避免忙等)

Mutual exclusion(互斥)

  • 当一个进程处于临界区并访问共享资源时,没有其他进程会处于临界区并且访问任何相同的共享资源
  • 同一时间临界区中最多存在一个线程

方法1:禁用硬件中断

思路

  • 线程执行前设置中断屏蔽,执行完成之后消除中断屏蔽

问题

  • 一旦中断被禁用,线程就无法被停止
    • 整个系统都会为该进程停下来
    • 可能导致其他线程处于饥饿状态
  • 无法限制响应中断所需的时间

局限性

  • 对临界区很小的系统是有效的
  • 对多CPU的作用是有限的

方法2:基于软件的解决方法

满足进程Pi和Pj之间互斥的经典的基于软件的解决方法:使用两个共享数据项

  • int turn; //指示该谁进入临界区
  • boolean flag[]; //指示进程是否准备好进入临界区
  • 满足互斥、有限等待、前进这三个属性

进入临界区

  • flag[i] = TRUE;
  • turn = j; //turn为0或1
  • while(flag[j] && turn == j); //如果成立那么Pi等待

退出临界区

  • flag[i] = FALSE;

方法3:更高级的抽象

硬件提供了一些原语

  • 像中断禁用,原子操作指令等
  • 大多数现代体系结构都是这样

操作系统提供更高级的编程抽象来简化并行编程

  • 例如:锁、信号量
  • 从硬件原语中构建

大多数现代体系结构都提供特殊的原子操作指令

  • 通过特殊的内存访问电路
  • 针对单处理器和多处理器

特殊的原子操作指令

  • Test-and-Set 测试和置位(不会被打断)

    • 从内存中读取值
    • 测试该值是否为1,并返回真假
    • 内存值置为1
  • 交换

    • 交换内存中的两个值

使用特殊原子操作的优点

  • 适用于单处理器或者共享主存的多处理器中任意数量的进程
  • 简单并且容易证明
  • 可以支持多临界区

使用特殊原子操作的缺点

  • 忙等待消耗处理器时间
  • 饥饿:当进程离开临界区并且多个进程在等待时可能导致饥饿
  • 死锁:如果一个低优先级的进程拥有临界区并且一个高优先级进程也需求,那么高优先级进程会获得处理器并等待临界区

总结

在这里插入图片描述

  • 锁可以实现互斥,通常需要一定的硬件支持
  • 常用的三种实现方法:
    • 禁用中断(仅限于单处理器)
    • 软件方法(复杂)
    • 原子操作指令(单处理器或多处理器均可)
  • 可选的实现内容:
    • 有忙等待
    • 无忙等待

猜你喜欢

转载自blog.csdn.net/MaoziYa/article/details/106481567
今日推荐