操作系统笔记(3)——同步与互斥

这篇博客详细介绍了操作系统的同步与互斥概念,包括临界资源、临界区的定义,以及互斥的硬件(中断屏蔽法、原子硬件指令)和软件实现方法。通过信号量机制解释了如何实现同步和互斥,并提供了多个同步问题的实例,如生产者-消费者问题、读者-写者问题等,帮助读者深入理解这些概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

启蒙篇

在这里插入图片描述

基础篇

  • 并发性:cpu可以分时间段交替执行不同程序代码

1.临界资源&临界区

  • 临界资源:一次只能被一个进程所使用的资源

    • eg:
      • 硬件——打印机、网卡、键盘
      • 软件——共享变量
  • 临界区:每个进程中访问临界资源的那段代码成为临界区

    • 每个进程在进入临界区之前,应先对欲访问的临界资源进行检查,看他是否正在被访问
      • 若是则进程不能进入临界区
      • 若否则可以进入访问,并设置其正被访问的标志

2.同步与互斥

进程(线程)之间的两种关系:同步与互斥。

  • 所谓互斥,是指散布在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时,其它进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行
  • 所谓同步,是指散布在不同进程之间的若干程序片断,它们的运行必须严格按照规定的 某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。

同步是一种更为复杂的互斥,而互斥是一种特殊的同步。也就是说互斥是两个线程之间不可以同时运行,他们会相互排斥,必须等待一个线程运行完毕,另一个才能运行,而同步也是不能同时运行,但他是必须要安照某种次序来运行相应的线程(也是一种互斥)!

总结
  • 互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的
  • 同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

3.互斥的实现

硬件方法
中断屏蔽法
    • 提要:
    • 调度时机大概可以分为三种
      • 程序结束时 —— 已经没有竞争对手,不需要互斥
      • I/O请求时
      • 时间片用完时
    • 这三种都属于中断
  • 只允许cpu为一个进程服务

  • 中断屏蔽法本质上是将cpu“麻痹”,令其无法接收到中断信号,如此一来就无法完成切换操作,自然可以让cpu只服务于一个进程

  • 此种方法只能作用于后两种:I/O请求和时间片用完

原子硬件指令法(Test And Set、Swap)
  • Test And Set、Swap是一个硬件电路,特点是不会受到中断信号的干扰,无论如何都会执行完指定段代码
软件方法
  • 单标志法

    • 轮流传递的思想(令牌环网)
    • 生死系于别人(缺点)
    • turn的编号与自己编号相符时则使用,使用完毕后更改编号传递至下一个人
  • 双标志先检查法 —— 每个人都有自己的标志(无需等待令牌了)

    • 通过设置flag值的真伪来判断对方是否要使用cpu。若对方不使用则自己用
    • 可以理解为两人相互谦让,但是比较容易产生bug
      • 若双方看对方均为false,则同时请求使用cpu时也会产生冲突
      • 若双方看对方均为true,则陷入等待
  • 双标志后检查法

    • 一开始就将flag设置为true,此后再进行判断对方是否请求
    • 可以理解为双方争执,可能会出现争执不下而都无法使用(无限等待 + 饥饿)
  • Peterson's算法(真正实现互斥)

    • 双方开始将flag置于true,但夺取cpu资源之前会观察对方,避免太过“强势”而造成的无限等待和饥饿问题

    • Faker(){
          while(1){
              flag[0] = true;  	//资源是自己的
              turn = 1;			//留一手,如果你也想要可以先让给你
              white(flag[1] && turn == 1){
                  if(gun == 1){
                      gun = Faker;
                  }else{
                      ;
                  }
                  flag[0] = false;
              }
          }
      }
      
      Rookie(){
          while(1){
              flag[0] = true;  	//资源是自己的
              turn = 1;			//留一手,如果你也想要可以先让给你
              white(flag[0] && turn == 0){
                  if(gun == 1){
                      gun = Rookie;
                  }else{
                      ;
                  }
                  flag[0] = false;
              }
          }
      }
      
    • 如代码所示,cpu上优先级上Rookie更高

    • 后台更改数据为最终的数据

4.信号量

由来
  • P、V操作:
    • P(等待):等待进入临界区
    • V(释放):从临界区中出来释放资源
工作原理

在这里插入图片描述

typedef struct{
   
   
    int value;			    //值
    struct process *L;		//阻塞队列  PCB
}semephore;		//信号量

//S.value 的初始值很重要,可以决定最多有几个进程同时运行
//S.value > 0 时		有资源,直接入驻。资源数减一
//S.value = 0 时		刚好无资源,排队等待
//S.value < 0 时		无资源,排队,自己是负几就排第几

void wait(semephore S){
   
   
    S.value--;
    if(S.value < 0){
   
   
        //本进程放弃cpu,进队本信号量的阻塞队列
    }
}
void signal(semephore S){
   
   
    S.value++;
    if(S.value <= 0){
   
   
        //唤醒本信号量队列的第一个进程,让其等待获取cpu继续运行
    }
}
信号量实现同步

此前我们提到了判别符S,其初值尤为重要,可以决定最多有几个进程同时运行

  • S > 0时 有资源,直接入驻。资源数减一
    S = 0时 刚好无资源,排队等待
    S < 0时 无资源,排队,自己是负几就排第几
  • eg:此题我们来通过控制信号量的值完成同步。此题中S = 0
// 同步模板
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值