先来先服务FCFS和短作业优先SJF进程调度算法(C++代码及文档)

一、实验目的

1、加深对进程概念的理解;
2、进一步掌握进程状态的转变、进程调度的策略及对系统性能的评价方法;

二、需求分析

2.1 程序设计任务

本程序的设计任务是模拟操作系统中的进程调度过程,具体实现先来先服务(FCFS)和短作业优先(SJF)调度算法。程序能够根据用户输入的进程信息,计算并输出各进程的完成时间、周转时间、带权周转时间,以及所有进程的平均周转时间和平均带权周转时间。

2.2 输入内容、形式范围

  • 进程个数 n(正整数,不超过1e4)
  • 每个进程的到达时间:arrivalTime(非负整数)
  • 每个进程的服务时间:serviceTime(正整数)
  • 选择调度算法(1=FCFS,2=SJF)

2.3 输出形式

  • 每个进程的开始时间
  • 每个进程的输出:完成时间、周转时间、带权周转时间
  • 总体:平均周转时间、平均带权周转时间

2.4 测试数据

2.4.1 正确的输入

2.4.2 错误的输入

  • 进程数超过1e4

  • 到达时间低于0

  • 服务时间不为正整数

  • 调度算法选择错误

三、概要设计

程序主要包括以下模块:

  • Process结构体:存储进程相关信息,包括进程的ID,到达时间,服务时间,完成时间,周转时间,带权周转时间
  • cmp函数:按到达时间对进程进行排序。
  • FCFS函数:实现先来先服务调度。
  • SJF函数:实现短作业优先调度。
  • calculateAverages函数:计算平均周转时间和带权周转时间。
  • main函数:程序入口,处理用户输入及调度算法选择。

流程如下:

  • 用户输入进程数量及进程到达时间、服务时间。
  • 根据用户选择的调度算法调用相应函数(FCFS或SJF)进行调度。
  • 输出每个进程的信息及平均时间。

四、详细设计

4.1 FCFS 算法实现

  1. 初始化当前时间为0。
  2. 遍历进程:
  • 更新当前时间为进程到达时间(如果当前时间小于到达时间)。
  • 计算并记录完成时间、周转时间、带权周转时间。
  1. 输出每个时间点的调度状态。

4.2 SJF 算法实现

  1. 初始化当前时间和剩余进程数。
  2. 在每个时间点寻找到达且尚未完成的进程中,服务时间最短的进程。
  3. 处理等待状态,用时间累加,直到所有进程完成。
  4. 输出每个时间点的调度状态。

4.3 计算所有进程的平均时间

对所有进程的周转时间与带权周转时间进行累加,计算平均值。

五、调试分析

5.1 调试过程中遇到的问题及解决方案

问题:运行SJF时,未完成进程的初始化导致无法找到可调度进程。

解决方案:在进程结构体中增加finishTime初始值为-1来标识尚未完成。

5.2 算法的时空复杂度分析

5.2.1 算法时间复杂度分析

(1) FCFS算法

FCFS是一种简单且直观的非抢占式调度算法,其时间复杂度主要由以下两部分构成:

  • 遍历进程列表: 每个进程在其到达时被调度执行。这一部分的时间复杂度为O(n),其中n为进程数量。
  • 计算时间相关参数: 每个进程的完成时间、周转时间及带权周转时间均在一次遍历中完成,因此该部分复杂度为O(1)。

总体来说,FCFS在每次算法执行中的时间复杂度为O(n)。

(2) SJF算法

SJF算法在其非抢占式形态下同样是个复杂的调度策略:

  • 查找当前可执行且服务时间最短的进程: 对于每一个调度决定,算法需遍历所有进程以确定当前可以调度的进程中服务时间最短者。这部分的时间复杂度为O(n)。
  • 更新时间和状态: 此操作与FCFS类似,为O(1)。

因此,在最坏情况下,SJF算法的时间复杂度为O(n^2),因为每个进程可能依次被分析n次。

5.2.2 算法空间复杂度分析

对于这两种算法,空间复杂度主要由存储进程信息的数据结构决定:

  • 进程数据结构: 需要额外的空间来存储处理器为每个进程维护的属性值(到达时间、服务时间等),该空间复杂度为O(n)。
  • 辅助变量: 包括当前时间和剩余未调度进程数等,空间复杂度为O(1),不随输入规模变化。

总的来说,FCFS和SJF的空间复杂度都为O(n)。

5.2.3 改进设想

随着进程数量的增加,尤其在处理规模较大时,现有实现中的时间效率可能会不尽人意。针对这一点,以下几种改进方案可被考虑:

  • 使用优先级队列: 对于SJF算法,将进程放入优先级队列可以直接获取当前服务时间最短的进程,将单次查找的时间复杂度从O(n)降低至O(log n)。
  • 引入抢占性: 使用抢占式的SJF(又称为Shortest Remaining Time First, SRTF),能更为动态地适应处理等待时间较长的进程,减少可能的饿死现象。
  • 并行处理: 在多核系统中,适用并行算法调度以提高效率,尤其是在大量进程需要同时计算属性值时。
  • 动态调整时间片: 在需要兼顾实时性时,可以参考Round Robin算法,结合时间片动态调整来保证公平。

5.3 经验和体会

在实现过程中,理解进程状态转变对调度算法的关键影响。

对算法的效率与稳定性有更深刻的认识。

六、用户使用说明

使用程序步骤如下:

  • 编译并运行程序。
  • 按提示输入进程个数 n 及每个进程的到达时间和服务时间。
  • 根据提示输入 1 选择FCFS算法或 2 选择SJF算法。
  • 查看输出结果,进程调度状态以及相关统计信息。

七、测试结果

输入:

FCFS结果:

SJF结果:

总结:

算法

进程名

A

B

C

D

E

平均

到达时间

0

1

2

3

4

服务时间

4

3

5

2

4

FCFS

完成时间

4

7

12

14

18

周转时间

4

6

10

11

14

9

带权周转时间

1

2

2

5.5

3.5

2.8

SJF

完成时间

4

9

18

6

13

周转时间

4

8

16

3

9

8

带权周转时间

1

2.67

3.2

1.5

2.25

2.12

代码

#include <bits/stdc++.h>
using namespace std;
struct Process {
    int id;                   
    int arrivalTime; // 到达时间
    int serviceTime; // 服务时间
    int finishTime; // 完成时间
    int wholeTime; // 周转时间
    double weightedWholeTime; // 带权周转时间
};

void FCFS(vector<Process>& processes) {
    int currentTime = 0;// 当前时间初始化为0
    for (auto& process : processes) {
        if (currentTime < process.arrivalTime) {
            currentTime = process.arrivalTime;// 当前时间小于进程到达时间时,更新当前时间
        }
        process.finishTime = currentTime + process.serviceTime;//计算
        process.wholeTime = process.finishTime - process.arrivalTime;
        process.weightedWholeTime = (double)process.wholeTime / process.serviceTime;

        currentTime = process.finishTime;// 更新当前时间
        cout << "时刻" << currentTime - process.serviceTime << ":进程" << process.id << "开始运行" << endl;
    }
}

void SJF(vector<Process>& processes) {
    int currentTime = 0;
    int remaining = processes.size();// 剩余需要调度的进程数量初始化为所有进程
    while (remaining > 0) {
        int minIndex = -1;
        int minServiceTime = INT_MAX;

        for (int i = 0; i < processes.size(); ++i) {
            // 找到当前时间前可执行且服务时间最短的进程
            if (processes[i].finishTime == -1 && processes[i].arrivalTime <= currentTime && processes[i].serviceTime < minServiceTime) {
                minServiceTime = processes[i].serviceTime;
                minIndex = i;
            }
        }

        if (minIndex == -1) {
            currentTime++;
        }
        else {
            processes[minIndex].finishTime = currentTime + processes[minIndex].serviceTime;
            processes[minIndex].wholeTime = processes[minIndex].finishTime - processes[minIndex].arrivalTime;
            processes[minIndex].weightedWholeTime = (double)processes[minIndex].wholeTime / processes[minIndex].serviceTime;

            cout << "时刻" << currentTime << ":进程" << processes[minIndex].id << "开始运行" << endl;
            currentTime = processes[minIndex].finishTime;//更新当前时间
            remaining--;// 剩余未完成进程数量减少
        }
    }
}
// 计算平均周转时间和平均带权周转时间
void calculateAverages(const vector<Process>& processes, double& averageWT, double& averageWWT) {
    int totalWT = 0;
    double totalWWT = 0.0;
    for (const auto& process : processes) {
        totalWT += process.wholeTime;
        totalWWT += process.weightedWholeTime;
    }
    averageWT = (double)totalWT / processes.size();
    averageWWT = totalWWT / processes.size();
}

int main() {
    int n;
    cout << "请输入进程个数: ";
    cin >> n;
    vector<Process> processes(n);
    if (n > 1e4) {
        cout << "进程数量太多" << endl;
        return 1;
    }

    cout << "请输入每个进程的到达时间和服务时间 (格式: 到达时间 空格 服务时间): " << endl;
    for (int i = 0; i < n; i++) {
        cout << "进程" << i + 1 << ": ";
        processes[i].id = i + 1;
        cin >> processes[i].arrivalTime >> processes[i].serviceTime;
        processes[i].finishTime = -1; // -1表示进程尚未完成
        if (processes[i].arrivalTime < 0) {
            cout << "到达时间不能低于0!请重新输入" << endl;
            i--;
        }
        else if (processes[i].serviceTime <= 0) {
            cout << "服务时间应为正整数!请重新输入" << endl;
            i--;
        }
    }
    
    int choice;
    cout << "选择调度算法 (1-FCFS, 2-SJF): ";
    cin >> choice;
    if (choice == 1) {
        FCFS(processes);
    }
    else if (choice == 2) {
        SJF(processes);
    }
    else {
        cerr << "无效的选择!";
        return 1;
    }

    double averageWT, averageWWT;
    calculateAverages(processes, averageWT, averageWWT);

    cout << "\n调度结果:" << endl;
    for (const auto& process : processes) {
        cout << "进程" << process.id << ":完成时间 = " << process.finishTime
            << ", 周转时间 = " << process.wholeTime
            << ", 带权周转时间 = " << process.weightedWholeTime << endl;
    }

    cout << "平均周转时间: " << averageWT << endl;
    cout << "平均带权周转时间: " << averageWWT << endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值