操作系统进程调度模拟:先来先服务(FCFS)算法

在模拟操作系统的进程调度时,先来先服务(FCFS)是一种最简单也最基础的调度策略。它按照进程到达的顺序服务于每个进程,形成一个排队系统。在本文中,我们将逐步实现一个简单的 FCFS 调度模拟,并通过代码和甘特图帮助你理解整个流程。

一、流程概述

在实现 FCFS 调度模拟前,我们需要明确整体的流程。下表 описывает了执行步骤:

步骤 描述
1 定义进程类及其属性(进程ID、到达时间、服务时间等)
2 创建进程实例,存储进程信息
3 按照到达时间对进程进行排序
4 计算每个进程的开始时间、完成时间与周转时间
5 展示进程的执行结果,以及生成甘特图

二、每一步详解

接下来,我们逐步进行代码的实现。

1. 定义进程类及其属性

首先,我们需要定义一个 Process 类,以便能够管理进程的相关信息。

class Process {
    int processId;     // 进程ID
    int arrivalTime;   // 到达时间
    int serviceTime;   // 服务时间
    int startTime;     // 开始时间
    int completionTime; // 完成时间
    int turnaroundTime; // 周转时间

    // 构造函数
    public Process(int id, int arrival, int service) {
        this.processId = id;
        this.arrivalTime = arrival;
        this.serviceTime = service;
    }

    // 计算周转时间
    public void calculateTurnaroundTime() {
        this.turnaroundTime = this.completionTime - this.arrivalTime;
    }
}

2. 创建进程实例

接下来,我们创建一组进程实例并存储其信息。

import java.util.ArrayList;
import java.util.List;

public class FCFSScheduler {
    List<Process> processes = new ArrayList<>(); // 存储进程的列表

    // 添加进程实例
    public void addProcess(int id, int arrival, int service) {
        processes.add(new Process(id, arrival, service));
    }
}

3. 按照到达时间进行排序

我们需要将进程根据到达时间进行排序,以便实现 FCFS 调度。

import java.util.Collections;
import java.util.Comparator;

public void sortProcessesByArrivalTime() {
    Collections.sort(processes, new Comparator<Process>() {
        @Override
        public int compare(Process p1, Process p2) {
            return Integer.compare(p1.arrivalTime, p2.arrivalTime);
        }
    });
}

4. 计算时间

接下来,我们需要计算每个进程的开始时间、完成时间和周转时间。

public void calculateTimes() {
    int currentTime = 0;
    for (Process p : processes) {
        if (currentTime < p.arrivalTime) {
            currentTime = p.arrivalTime; // 等待到达下一进程
        }
        p.startTime = currentTime; // 记录开始时间
        currentTime += p.serviceTime; // 更新当前时间
        p.completionTime = currentTime; // 记录完成时间
        p.calculateTurnaroundTime(); // 计算周转时间
    }
}

5. 展示结果与甘特图生成

最后,展示进程执行结果并生成甘特图。

public void displayResults() {
    System.out.println("进程ID\t到达时间\t服务时间\t开始时间\t完成时间\t周转时间");
    for (Process p : processes) {
        System.out.printf("%d\t%d\t%d\t%d\t%d\t%d\n", 
            p.processId, p.arrivalTime, p.serviceTime, 
            p.startTime, p.completionTime, p.turnaroundTime);
    }
    
    System.out.println("甘特图:");
    System.out.println("```mermaid");
    System.out.println("gantt");
    System.out.println("    title 进程调度甘特图");
    System.out.println("    dateFormat  HH:mm");
    for (Process p : processes) {
        System.out.printf("    section Process %d\n\t%f, %d\n", 
            p.processId, (double)p.startTime, p.serviceTime);
    }
    System.out.println("```");
}

完整程序

将上面的代码组合在一起,形成完整的程序:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class Process {
    int processId;     
    int arrivalTime;   
    int serviceTime;   
    int startTime;     
    int completionTime; 
    int turnaroundTime; 

    public Process(int id, int arrival, int service) {
        this.processId = id;
        this.arrivalTime = arrival;
        this.serviceTime = service;
    }

    public void calculateTurnaroundTime() {
        this.turnaroundTime = this.completionTime - this.arrivalTime;
    }
}

public class FCFSScheduler {
    List<Process> processes = new ArrayList<>(); 

    public void addProcess(int id, int arrival, int service) {
        processes.add(new Process(id, arrival, service));
    }

    public void sortProcessesByArrivalTime() {
        Collections.sort(processes, 
            (p1, p2) -> Integer.compare(p1.arrivalTime, p2.arrivalTime));
    }

    public void calculateTimes() {
        int currentTime = 0;
        for (Process p : processes) {
            if (currentTime < p.arrivalTime) {
                currentTime = p.arrivalTime; 
            }
            p.startTime = currentTime; 
            currentTime += p.serviceTime; 
            p.completionTime = currentTime; 
            p.calculateTurnaroundTime(); 
        }
    }

    public void displayResults() {
        System.out.println("进程ID\t到达时间\t服务时间\t开始时间\t完成时间\t周转时间");
        for (Process p : processes) {
            System.out.printf("%d\t%d\t%d\t%d\t%d\t%d\n", 
                p.processId, p.arrivalTime, p.serviceTime, 
                p.startTime, p.completionTime, p.turnaroundTime);
        }

        System.out.println("甘特图:");
        System.out.println("```mermaid");
        System.out.println("gantt");
        System.out.println("    title 进程调度甘特图");
        System.out.println("    dateFormat  HH:mm");
        for (Process p : processes) {
            System.out.printf("    section Process %d\n\t%f, %d\n", 
                p.processId, (double)p.startTime, p.serviceTime);
        }
        System.out.println("```");
    }

    public static void main(String[] args) {
        FCFSScheduler scheduler = new FCFSScheduler();
        scheduler.addProcess(1, 0, 5);
        scheduler.addProcess(2, 1, 3);
        scheduler.addProcess(3, 2, 8);
        scheduler.addProcess(4, 3, 6);
        
        scheduler.sortProcessesByArrivalTime();
        scheduler.calculateTimes();
        scheduler.displayResults();
    }
}

三、结语

在这篇文章中,我们详细介绍了如何实现操作系统进程调度模拟中的先来先服务(FCFS)算法。通过简单的类结构和明了的步骤,我们成功地完成了进程调度的模拟。了解这些基本概念,不仅让你在开发中更加得心应手,还能为后续学习更高级的调度算法打下坚实的基础。希望这篇文章对你有所帮助!