操作系统学习一: NetCore 实现模拟多道程序设计的简单处理机调用

前言

道程序设计中,经常是若干个进程同时处于就绪状态,为了使系统中的各进程有条不紊地运行,必须选择某种调度策略,以选择一个进程占用处理机。本次实验设计一个模拟单处理机调度的算法,以加深对处理机调度算法的理解。

要求

  1. 按照时间片轮转算法设计模拟调度程序。
  2. 输出进程的调度过程。

思路分析

由于本实验是按照处理机调度算法模拟实现处理机的调度,与真正的处理机调度过程并不完全相同,比如没有实现中断(时间片设为1),进程的运行也不是真正的运行,而是在屏幕上打印其运行时间等。所以要以文件的形式给出进程的信息,文件信息可参考如下:

进程ID  到达时间     估计运行时间     优先级
0        0             3               2
1        2             6               4
2        4             4               0
3        6             5               3
4        8             2               1  

以下是实验的大致思路: 1. 建立三个队列:PCB队列,就绪队列,完成队列。 PCB队列:保存将进入系统的进程。(由于没有实现中断,所以将进入系统运行的进程必须在程序运行前给出)。 就绪队列:到达进程进入系统的时间,将该进程放入就绪队列,等待调度。 完成队列:将“运行”完的进程放入完成队列。

  1. 进程运行过程是在屏幕上打印相关信息。 使用轮转算法调度的进程应打印的信息包括:进程占用处理机序列,该进程每次占用处理机的开始时间与结束时间。

  2. 统计出进程的周转时间T和带权周转时间W。

流程图

实现代码

  1. ProcessControlBlock.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace OperatingSystemExperiment.Exp1 {
        enum ProcessStatus {
            Ready,
            Run,
            Finish
        }
    
        /// <summary>
        /// 进程控制块 PCB
        /// </summary>
        class ProcessControlBlock {
            /// <summary>
            /// 进程号
            /// </summary>
            public int ID;
    
            /// <summary>
            /// 进程状态
            /// </summary>
            public ProcessStatus Status;
    
            /// <summary>
            /// 进程到达时间
            /// </summary>
            public int ArriveTime;
    
            /// <summary>
            /// 估计运行时间
            /// </summary>
            public int Time;
    
            /// <summary>
            /// 已运行时间
            /// </summary>
            public int RunTime = 0;
    
            /// <summary>
            /// 等待时间
            /// </summary>
            public int WaitTime;
    
            /// <summary>
            /// 优先级
            /// </summary>
            public int Priority;
    
            /// <summary>
            /// 链接指针
            /// </summary>
            public ProcessControlBlock Next;
    
            /// <summary>
            /// 开始时间
            /// </summary>
            public int StartTime;
    
            /// <summary>
            /// 结束时间
            /// </summary>
            public int FinishTime;
    
            public void Run()
            {
                this.Status = ProcessStatus.Run;
    
                if (RunTime >= Time) {
                    this.Status = ProcessStatus.Finish;
                    return;
                }
    
                this.RunTime++;
            }
    
            public void Wait()
            {
                this.WaitTime++;
            }
    
            public override string ToString() => String.Format("{0} {1} {2}", ID, StartTime, FinishTime);
        }
    }
    

  2. CentralProcessUnit.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.IO;
    
    namespace OperatingSystemExperiment.Exp1 {
        class CentralProcessUnit {
            private List<ProcessControlBlock> PCBList = new List<ProcessControlBlock>();
            private Queue<ProcessControlBlock> FinishQueue = new Queue<ProcessControlBlock>();
            private Queue<ProcessControlBlock> ReadyQueue = new Queue<ProcessControlBlock>();
    
            public CentralProcessUnit()
            {
                LoadPcbList();
            } 
    
            /// <summary>
            /// 生成进程列表
            /// </summary>
            /// <param name="count">进程数量</param>
            public static void GenerateProcessList(int count)
            {
                var processListFile = Path.Combine(Environment.CurrentDirectory, "process_list.txt");
                var writer = new StreamWriter(processListFile);
                var rnd = new Random(DateTime.Now.Millisecond);
                for (var i = 0; i < count; i++) {
                    var runTime = rnd.Next(1, 10);
                    writer.WriteLine("{0} {1} {2} {3}", i, Math.Pow(2, i), runTime, rnd.Next(0, 4));
                }
    
                writer.Close();
            }
    
            /// <summary>
            /// 加载PCB列表
            /// </summary>
            private void LoadPcbList()
            {
                var processListFile = Path.Combine(Environment.CurrentDirectory, "process_list.txt");
                var reader = new StreamReader(processListFile);
                while (!reader.EndOfStream) {
                    var line = reader.ReadLine();
                    var procInfo = line.Split(' ');
                    PCBList.Add(new ProcessControlBlock {
                        ID = int.Parse(procInfo[0]),
                        ArriveTime = int.Parse(procInfo[1]),
                        Time = int.Parse(procInfo[2]),
                        Priority = int.Parse(procInfo[3])
                    });
                }
            }
    
            /// <summary>
            /// CPU运行
            /// </summary>
            public void Run()
            {
                var times = 0;
                while (true) {
                    // 如果所有进程运行完,则退出循环
                    if (FinishQueue.Count == PCBList.Count) {
                        break;
                    }
    
                    // 遍历所有进程列表
                    foreach (var p in PCBList) {
                        // 根据进程到达时间判定是否有新进程加入,然后将进程状态设置为就绪
                        if (p.ArriveTime == times++) {
                            Console.WriteLine("时间:{0},进程 {1} 到达", times, p.ID);
                            p.Status = ProcessStatus.Ready;
                        }
    
                        // 讲就绪状态进程加入就绪列表
                        if (p.Status == ProcessStatus.Ready) {
    //                        Console.WriteLine("时间:{0},进程 {1} 加入就绪列表", times, p.ID);
                            ReadyQueue.Enqueue(p);
                        }
    
                        // 如果就绪队列为空则进入下一次循环
                        if (ReadyQueue.Count == 0) {
    //                        Console.WriteLine("时间:{0},没有就绪进程,进入下一个循环", times);
                            continue;
                        }
    
                        // 从就绪队列中取出一个进程运行
                        var currentProcess = ReadyQueue.Dequeue();
                        Console.WriteLine("时间:{0},运行进程 {1}", times, p.ID);
                        currentProcess.Run();
    
                        // 将运行完毕进程加入完成列表
                        if (currentProcess.Status == ProcessStatus.Finish) {
                            Console.WriteLine("时间:{0},进程 {1} 运行完毕,总运行时间:{2}", times, p.ID, p.RunTime);
                            FinishQueue.Enqueue(currentProcess);
                        }
                        else
                            currentProcess.Status = ProcessStatus.Ready;
                    }
                }
            }
        }
    }
    

  3. Main.cs

    namespace OperatingSystemExperiment.Exp1
    {
        public class Main
        {
            public static void Run()
            {
                CentralProcessUnit.GenerateProcessList(5);
                new CentralProcessUnit().Run();
            }
        }
    }
    

运行结果

  • 生成的process_list.txt内容:

    0 1 8 3
    1 2 3 1
    2 4 8 0
    3 8 6 3
    4 16 4 1
    

  • 控制台输出 时间:1,运行进程 0 时间:2,运行进程 1 时间:3,运行进程 2 时间:4,运行进程 3 时间:5,运行进程 4 时间:6,运行进程 0 时间:7,运行进程 1 时间:8,运行进程 2 时间:9,进程 3 到达 时间:9,运行进程 3 时间:10,运行进程 4 时间:11,运行进程 0 时间:12,运行进程 1 时间:13,运行进程 2 时间:14,运行进程 3 时间:15,运行进程 4 时间:16,运行进程 0 时间:17,运行进程 1 时间:17,进程 1 运行完毕,总运行时间:3 时间:18,运行进程 2 时间:19,运行进程 3 时间:20,运行进程 4 时间:21,运行进程 0 时间:23,运行进程 2 时间:24,运行进程 3 时间:25,运行进程 4 时间:25,进程 4 运行完毕,总运行时间:4 时间:26,运行进程 0 时间:28,运行进程 2 时间:29,运行进程 3 时间:31,运行进程 0 时间:33,运行进程 2 时间:34,运行进程 3 时间:34,进程 3 运行完毕,总运行时间:6 时间:36,运行进程 0 时间:38,运行进程 2 时间:41,运行进程 0 时间:41,进程 0 运行完毕,总运行时间:8 时间:43,运行进程 2 时间:43,进程 2 运行完毕,总运行时间:8

欢迎与我交流