哈工大李治军老师OS课程笔记(3)——CPU的调度,进程同步与信号量,死锁处理

本文详细探讨了CPU调度算法(FCFS、SJF、RR和优先级调度)以及进程同步中的信号量、临界区保护(Peterson算法、面包店算法),还介绍了死锁的成因、条件和处理方法,以及条件变量与信号量的区别。
摘要由CSDN通过智能技术生成

一 、CPU调度

在一堆就绪队列中,选择哪个进程执行。如何设计调度算法呢?对于用户来说等待时间越短越好。要让进程满意,做到以下三点:

  • 周转时间短(从任务进入到任务结束),尽快结束任务
  • 响应时间快(从操作发生到响应):用户操作尽快响应
  • 吞吐量大(完成的任务量):系统内耗的时间少

调度算法总原则:系统专注于任务执行,又能合理调配任务。需要折中,需要综合

不同类型的任务有其特点和关注点。任务按照主体不同,分为以下两类:

  • 前台任务和后台任务
    关注点不同,前台关注响应时间,后台关注周转时间。
  • IO约束型任务和CPU约束型任务,IO约束型任务大多都是前台任务

一个矛盾点:吞吐量和响应时间之间存在矛盾。在这里插入图片描述
要考虑各个任务的特点,折中和综合让操作系统调度变得很复杂,下面介绍常见的CPU调度算法

1、FCFS(First Come,First Served,先来先服务)——最公平

2、SJF(短作业优先)—— 平均周转时间最短

  • 最小化等待时间:SJF算法选择执行时间最短的作业,这意味着较短的作业将更早地得到执行。因此,对于长时间的作业,其他作业需要等待的时间会相对较长,而短作业可以更快地完成。这样可以最小化作业的等待时间,从而减少整体的平均周转时间。
  • 最大化CPU利用率:由于SJF算法选择执行时间最短的作业,CPU的利用率相对较高。较短的作业会更快地释放CPU资源,使其他作业有更多机会获得CPU时间。这样可以提高CPU的利用率,从而减少作业的等待时间和平均周转时间。

平均周转时间(Average Turnaround Time)是衡量作业或进程调度算法性能的指标之一,它表示从作业提交到作业完成所经过的平均时间。计算平均周转时间的方法如下:
1.对于每个作业或进程,计算其周转时间(Turnaround Time):周转时间 = 完成时间 - 提交时间(提交时间不等于开始时间,提交了不一定立马开始
2.对所有作业或进程的周转时间进行求和。
3.平均周转时间 = 总的周转时间 / 作业或进程的数量.

在这里插入图片描述

3、RR(按时间片轮转调度)

时间片大:响应时间长;时间片小:吞吐量小,根据实际情况折衷设置

4、优先级调度

一个调度算法如何让多种类型的任务满意?一个直观的想法是定义前台任务和后台任务两队列,前台RR,后台SJF,只有前台任务没有时才调度后台任务。
在这里插入图片描述
存在的问题:

  • 固定优先级可能会导致后台任务饥饿,前台任务优先级高于后台任务,前台一直有任务来,一直执行,导致后台任务无法执行。
  • 优先级变化,后台任务优先级提高,后台任务往往是CPU很长的任务,比如编译很大的C文件,导致很长时间不释放CPU,导致前台任务响应时间短。

调度算法应该具有一定的学习能力在这里插入图片描述

5、schedule()函数

schedule会根据counter切换进程,counter既承担了时间片的作用,又承担了优先级的作用,在以下两种情况修改counter:

  • 每次进程调度,counter都会变化,假设counter=p,counter>>1+ p。
  • 每次时钟中断,都会执行counter–。

counter的作用:

  • 保证了响应时间的界,在响应时间不断变化的情况下。
  • 经过IO以后,counter就会变大;IO时间越长,counter越大,照顾了IO进程,也照顾了前台进程。
  • 后台进程一直按照counter轮转,近似SJF调度。
  • 每个进程只用维护一个counter变量,简单又高效。

二、进程同步与信号量

进程合作:多个进程共同完成一个任务。每个进程的语句不能随便执行,有些语句需要等待一个信号才能执行。

假设现在有司机进程和售票员进程,这两个进程要共同合作完成车辆的运行,如果司机不理售票,门没关好就启动车辆,容易引发事故。司机要等售票员关好门后启动车辆,将门关闭比作信号,司机看到了信号,启动车辆。
在这里插入图片描述

让“进程走走停停”来保证多进程的合理有序。进程同步(Process Synchronization)是指协调和控制进程或线程之间的执行顺序,以保证它们正确地共享和操作共享资源。

在这里插入图片描述
在生产者-消费者问题中,不仅要知道缓冲区空闲的个数,还需要知道睡眠的进程数量。信号counter的含义不能反映出正在睡眠的进程数量。等待信号和发信号对应睡眠和唤醒,因此还需要另一个量来决定要不要发信号,用信号量来记录一些信息,根据这个信息决定是唤醒还是睡眠。

信号量的实现当信号量的值小于0时,表示有进程或线程正在等待资源,资源当前不可用。当资源变为可用时,等待的进程或线程将被唤醒并获得资源的访问权限。

用信号量解决生产者-消费者问题

semaphore full = 0;
semaphore empty =BUFFER_SIZE;
semaphore  mutex = 1; // 互斥信号量,一次只有一个进程操作缓冲区

P函数表示睡眠,V函数表示唤醒
在这里插入图片描述

在C语言中,P函数的原型是:

#include<semaphore.h>
int sem_wait(sem_t *sem);

sem_wait函数的作用是将信号量的值减一(如果大于零),或者阻塞线程(如果信号量的值为零)。如果信号量的值大于零,则减一操作会立即返回,线程可以继续执行。如果信号量的值为零,则线程将进入阻塞状态,直到有其他线程增加信号量的值

在C语言中,V函数的原型是:

#include<semaphore.h>
int sem_post(sem_t *sem);

sem_post函数的作用是将信号量的值加一,但并不会阻塞当前线程的执行。如果有其他线程正在等待该信号量,则其中一个等待的线程会被唤醒,从而可以继续执行。

三、信号量临界区保护

信号量用来实现进程同步,但是当多个进程共同修改信号量时,会导致信号量语义发生错误,这种错误和调度顺序有关,所以要对信号量进行保护。
在这里插入图片描述
临界区:一次只允许一个进程进入的该进程的那一段代码。读写信号量的代码一定是临界区
在这里插入图片描述
临界区代码的保护原则

  • 基本原则:互斥进入:如果一个进程在临界区中执行,则其他进程不允许进入。
    • 这些进程间的约束关系称为互斥。
  • 好的临界区保护原则
    • 有空让进:若干进程要求进入空闲临界区时,应尽快使一些进程进入临界区。
    • 有限等待:从进程发出进入请求到允许进入,不能无限等待。
      在这里插入图片描述

1、Peterson算法

Peterson算法实现了两个进程之间的互斥操作,确保同一时间只有一个进程可以进入临界区执行操作,从而避免竞态条件的发生,结合了标记和轮转两种思想(turn负责轮换,flag负责做标记)。

在这里插入图片描述
Peterson算法代码示例
在这里插入图片描述

Peterson算法正确性
在这里插入图片描述
需要注意的是,Peterson算法是用于两个进程的情况,并且在某些特定的硬件和操作系统环境下可能存在问题。

2、面包店算法

用面包店算法,保护多个进程同步之间的信号量。面包店算法仍然是标记法加轮转法的结合,只是需给进程标号。

  • 如何轮转:每个进程都获得一个序号,序号最小的进入。
  • 如何标记:进程离开时序号为0,不为0的序号被标记。

面包店算法的正确性
在这里插入图片描述

3、关中断

cli(); #关中断
临界区
sti();#开中断

这种方式在多CPU情况下失效。

4、硬件原子指令

while(TestAndSet(&lock));
	临界区
	lock = false;
	剩余区

TestAndSet(boolean &x)
{
	boolean rv = x;
	x = true;
	return rv'
}

四、死锁处理

死锁是多线程或多进程并发程序中的一种常见问题,指的是两个或多个进程(或线程)互相等待对方释放资源,导致它们都无法继续执行的状态。

1、死锁成因

  • 资源互斥使用,一旦占有别人无法使用。
    在这里插入图片描述

  • 进程占有了一些资源,又不释放,再去申请其他资源。
    在这里插入图片描述

  • 各自占有的资源和互相申请的资源形成环路等待

2、死锁的4个必要条件

  • 互斥使用,资源的固有特性
  • 不可抢占,资源只能自愿放弃
  • 请求和保持,进程必须占有资源,再去申请
  • 循环等待,在资源分配图中存在一个环路

3、死锁处理方法概述

  • 死锁预防,破坏死锁出现的条件
  • 死锁避免,检测到煤气超标时,自动切断电路(银行家算法)
  • 死锁检测+恢复,检测死锁出现时,让一些进程回滚,让出资源
  • 死锁忽略,就好像没有死锁样(一般用这个方法,死锁了就重启)

五、条件变量与信号量的区别

下图分别是使用信号量和条件变量实现生产者-消费者问题的生产者代码示例:
在这里插入图片描述

  • 信号量是一个计数器,用于控制对共享资源的访问。它可以用于线程间的同步和互斥,通过对信号量的原子操作来实现。
  • 条件变量是基于互斥锁(mutex)和等待队列的机制。它允许线程通过等待操作阻塞自己,并在条件满足时被唤醒。其他线程可以通过条件变量的信号(pthread_cond_signal)或广播(如pthread_cond_broadcast)唤醒等待的线程。被唤醒的线程会重新尝试获取互斥锁,继续执行。

自旋
自旋也是一种线程同步的技术,和条件变量类似,只是在自旋中,线程在等待某个条件满足时不会阻塞自己,二是通过忙等待的方式持续检查条件是否满足。

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值