短作业优先调度算法详解:抢占式与非抢占式

在操作系统中,CPU调度算法决定了如何将有限的CPU时间分配给等待执行的进程。调度算法对系统性能、响应时间以及整体用户体验有着直接的影响。在众多的调度算法中,短作业优先(Shortest Job First, SJF) 是一种以最小化平均等待时间为目标的经典算法。SJF算法可以分为非抢占式抢占式两种形式,本文将详细讨论它们的特点、优点以及缺点。

什么是短作业优先算法?

短作业优先(SJF)是一种调度策略,它选择执行时间最短的进程优先进行调度。这种算法的核心理念是:短的任务先执行,从而减少整体的平均等待时间。

根据SJF的行为方式,调度可以分为两种类型:

  • 非抢占式短作业优先

  • 抢占式短作业优先(也称为最短剩余时间优先

非抢占式短作业优先算法

非抢占式短作业优先(Non-Preemptive SJF)中,一旦CPU分配给某个进程,直到该进程完成,CPU才会被释放。调度器每次选择就绪队列中预计执行时间最短的进程来执行。

工作机制
  1. 当一个新进程进入就绪队列时,调度器将查看所有进程的预计执行时间。

  2. 选择预计执行时间最短的进程,并将CPU分配给它。

  3. 一旦一个进程开始执行,除非该进程自己完成,否则不会被其他进程中断。

优点
  • 减少平均等待时间:由于优先执行短任务,较短的进程可以快速完成,从而降低整体的等待时间。

  • 实现简单:非抢占式调度机制相对简单,不需要额外的进程切换,适合某些特定的场景。

缺点
  • 长任务可能被长期推迟:如果有源源不断的新短任务进入就绪队列,那么长任务可能会长时间得不到执行,甚至可能导致饥饿(starvation)。

  • 无法处理突发事件:一旦分配CPU,不会有中断机制处理紧急任务。

举例

假设有四个进程P1、P2、P3、P4,预计执行时间分别为6、8、7、3个时间单位,它们都在时间点0进入系统。

进程执行时间(单位)
P16
P28
P37
P43
  • 调度顺序为:P4 -> P1 -> P3 -> P2

  • 平均等待时间为:(0 + 3 + 9 + 16) / 4 = 7 个时间单位

抢占式短作业优先算法(最短剩余时间优先)

抢占式短作业优先(Preemptive SJF)中,又称为最短剩余时间优先(Shortest Remaining Time First, SRTF),每当一个新进程到达时,调度器会比较新进程的执行时间与当前进程的剩余执行时间,如果新进程的执行时间更短,则会抢占当前的进程。

工作机制
  1. 初始化时,将所有进程的剩余时间设为其初始的执行时间。

  2. 当前时间为0,找到最早到达且剩余执行时间最短的进程执行。

  3. 每当有新进程到达时,调度器会重新检查所有未完成进程的剩余时间,选择剩余时间最短的进程执行。如果新进程的剩余时间更短,则会抢占当前的进程。

  4. 当一个进程的剩余时间变为0时,该进程完成,记录其完成时间。

  5. 重复上述步骤,直到所有进程都完成。

优点
  • 提高系统响应速度:对于短任务可以尽快完成,提高了系统的响应能力。

  • 较低的平均等待时间:抢占式SJF能更好地降低平均等待时间,因为它随时确保执行剩余时间最短的任务。

缺点
  • 高开销:频繁的进程切换可能导致上下文切换的开销增加,影响整体性能。

  • 饥饿问题:与非抢占式SJF类似,长任务在有大量短任务不断进入的情况下可能长时间得不到执行。

举例

假设有四个进程P1、P2、P3、P4,预计执行时间分别为6、8、7、3个时间单位。它们进入系统的时间点为:

进程到达时间执行时间(单位)
P106
P218
P327
P433

根据SRTF调度:

  1. 时间0到1:P1开始执行,剩余时间为5。

  2. 时间1到3:P2到达,但P1的剩余时间更短,P1继续执行。

  3. 时间3:P4到达,预计执行时间为3,P1被抢占,P4开始执行。

  4. 时间3到6:P4执行完成。

  5. 时间6到7:P1继续执行,剩余时间变为4。

  6. 时间7到10:P3到达并执行,剩余时间为4。

  7. 时间10以后继续进行剩余进程的调度。

比较与应用场景
  • 非抢占式SJF适用于那些需要减少调度开销、不要求高实时性的场景,比如批处理系统。

  • 抢占式SJF适合对响应时间要求较高的系统,比如交互式系统和某些实时操作系统。

结论

短作业优先(SJF)是一种有效的调度算法,尤其适合在任务执行时间已知的情况下,它能够最小化平均等待时间。然而,无论是抢占式还是非抢占式SJF,都会面临饥饿问题。为了解决这个问题,操作系统中常常引入老化(Aging)机制来确保长时间未执行的进程能得到执行机会。

对于理解操作系统中的进程调度,SJF是一个重要的起点。它展示了调度算法如何通过对任务长度的不同优先级分配来优化系统性能。希望这篇文章能帮助你更好地理解短作业优先调度算法的工作机制与应用场景。

C语言实现

以下是两种短作业优先调度算法的C语言实现。

非抢占式短作业优先(Non-Preemptive SJF)
#include <stdio.h>

void sjf_non_preemptive(int n, int burst_times[]) {
    int wait_times[n], turnaround_times[n];
    int total_wait = 0, total_turnaround = 0;
    int completed[n];

    // 初始化
    for (int i = 0; i < n; i++) {
        completed[i] = 0;
    }

    for (int i = 0; i < n; i++) {
        int min_index = -1;
        for (int j = 0; j < n; j++) {
            if (!completed[j] && (min_index == -1 || burst_times[j] < burst_times[min_index])) {
                min_index = j;
            }
        }
        completed[min_index] = 1;
        wait_times[min_index] = total_wait;
        total_wait += burst_times[min_index];
        turnaround_times[min_index] = wait_times[min_index] + burst_times[min_index];
        total_turnaround += turnaround_times[min_index];
    }

    printf("Process\tBurst Time\tWait Time\tTurnaround Time\n");
    for (int i = 0; i < n; i++) {
        printf("P%d\t\t%d\t\t%d\t\t%d\n", i + 1, burst_times[i], wait_times[i], turnaround_times[i]);
    }
    printf("Average Wait Time: %.2f\n", (float)total_wait / n);
    printf("Average Turnaround Time: %.2f\n", (float)total_turnaround / n);
}

int main() {
    int burst_times[] = {6, 8, 7, 3};
    int n = sizeof(burst_times) / sizeof(burst_times[0]);
    sjf_non_preemptive(n, burst_times);
    return 0;
}
抢占式短作业优先(Preemptive SJF)
#include <stdio.h>

void sjf_preemptive(int n, int arrival_times[], int burst_times[]) {
    int remaining_times[n], wait_times[n], turnaround_times[n];
    int total_wait = 0, total_turnaround = 0;
    int completed = 0, current_time = 0, min_index;

    // 初始化
    for (int i = 0; i < n; i++) {
        remaining_times[i] = burst_times[i];
    }

    while (completed != n) {
        min_index = -1;
        for (int i = 0; i < n; i++) {
            if (arrival_times[i] <= current_time && remaining_times[i] > 0) {
                if (min_index == -1 || remaining_times[i] < remaining_times[min_index]) {
                    min_index = i;
                }
            }
        }

        if (min_index == -1) {
            current_time++;
            continue;
        }

        remaining_times[min_index]--;
        current_time++;

        if (remaining_times[min_index] == 0) {
            completed++;
            turnaround_times[min_index] = current_time - arrival_times[min_index];
            wait_times[min_index] = turnaround_times[min_index] - burst_times[min_index];
            total_wait += wait_times[min_index];
            total_turnaround += turnaround_times[min_index];
        }
    }

    printf("Process\tArrival Time\tBurst Time\tWait Time\tTurnaround Time\n");
    for (int i = 0; i < n; i++) {
        printf("P%d\t\t%d\t\t%d\t\t%d\t\t%d\n", i + 1, arrival_times[i], burst_times[i], wait_times[i], turnaround_times[i]);
    }
    printf("Average Wait Time: %.2f\n", (float)total_wait / n);
    printf("Average Turnaround Time: %.2f\n", (float)total_turnaround / n);
}

int main() {
    int arrival_times[] = {0, 1, 2, 3};
    int burst_times[] = {6, 8, 7, 3};
    int n = sizeof(burst_times) / sizeof(burst_times[0]);
    sjf_preemptive(n, arrival_times, burst_times);
    return 0;
}

这两个实现展示了如何通过C语言实现非抢占式和抢占式短作业优先调度算法,帮助理解这两种调度方式的工作原理及其在代码中的实现。

1. 实验目的 调度的实质是操作系统按照某种预定的策略来分配资源。进程调度的目的是分配CPU资源。由于进程调度程序执行的频率很高,因此调度算法的好坏直接影响到操作系统的性能。本实验的目的是编程模拟实现几种常用的进程调度算法,通过对几组进程分别使用不同的调度算法,计算进程的平均周转时间和平均带权周转时间,比较各种算法的性能优劣。 2. 实验原理 [1]. 进程调度算法描述 进程调度算法包括先来先服务调度算法、最短作业时间优先(抢占式和非抢占式)、最高响应比调度算法4种。(每个人必须做FCFS,然后在后面的三种中任选一种,即每个人必须做2种调度算法的模拟。) [2]. 衡量算法性能的参数 计算进程的平均周转时间和平均带权周转时间。 3. 实验内容 (1)编程实现本实验的程序,要求: [1]. 建立进程的进程控制块,进程控制块至少包括: a) 进程名称; b) 进程需要执行时间; c) 进入就绪队列时间; d) 进程执行开始时间 e) 进程执行结束时间 [2]. 编程实现调度算法。 [3]. 进程及相关信息的输入。这些信息可以直接从键盘上输入,也可以从文件读取。 [4]. 时间片与时间流逝的模拟。本实验需要对算法的执行计时,程序应该提供计算时间的方法。一种最简单的方法是使用键盘,比如每敲一次空格代表一个时间片的流逝。另一种方法是使用系统时钟。 [5]. 一组进程序列执行完毕,打印出结果信息。程序需要计算出每个进程的开始执行时间、结束时间、周转时间和带权周转时间,并为整个进程序列计算平均周转时间和平均带权周转时间。程序将计算结果按一定的格式显示在计算机屏幕上或输出到文件中。打印出进程调度顺序图。 [6]. 实现数据在磁盘文件上的存取功能。 (2)对下列就绪进程序列分别使用上面的几种算法进行调度,计算每种算法下的平均周转时间和平均带权周转时间。 进程号 到达时间 要求执行时间 0 0 1 1 1 35 2 2 10 3 3 5 4 6 9 5 7 21 6 9 35 7 11 23 8 12 42 9 13 1 10 14 7 11 20 5 12 23 3 13 24 22 14 25 31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值