操作系统学习一:NetCore-实现模拟多道程序设计的简单处理机调用
前言 道程序设计中,经常是若干个进程同时处于就绪状态,为了使系统中的各进程有条不紊地运行,必须选择某种调度策略,以选择一个进程占用处理机。本次实验设计一个模拟单处理机调度的算法,以加深对处理机调度算法的理解。 要求 按照时间片轮转算法设计模拟调度程序。 输出进程的调度过程。 思路分析 由于本实验是按照处理机调度算法模拟实现处理机的调度,与真正的处理机调度过程并不完全相同,比如没有实现中断(时间片设
目录7 个章节
前言
道程序设计中,经常是若干个进程同时处于就绪状态,为了使系统中的各进程有条不紊地运行,必须选择某种调度策略,以选择一个进程占用处理机。本次实验设计一个模拟单处理机调度的算法,以加深对处理机调度算法的理解。
要求
- 按照时间片轮转算法设计模拟调度程序。
- 输出进程的调度过程。
思路分析
由于本实验是按照处理机调度算法模拟实现处理机的调度,与真正的处理机调度过程并不完全相同,比如没有实现中断(时间片设为1),进程的运行也不是真正的运行,而是在屏幕上打印其运行时间等。所以要以文件的形式给出进程的信息,文件信息可参考如下:
进程ID 到达时间 估计运行时间 优先级
0 0 3 2
1 2 6 4
2 4 4 0
3 6 5 3
4 8 2 1
以下是实验的大致思路:
-
建立三个队列:PCB队列,就绪队列,完成队列。 PCB队列:保存将进入系统的进程。(由于没有实现中断,所以将进入系统运行的进程必须在程序运行前给出)。 就绪队列:到达进程进入系统的时间,将该进程放入就绪队列,等待调度。 完成队列:将“运行”完的进程放入完成队列。
-
进程运行过程是在屏幕上打印相关信息。 使用轮转算法调度的进程应打印的信息包括:进程占用处理机序列,该进程每次占用处理机的开始时间与结束时间。
-
统计出进程的周转时间T和带权周转时间W。
流程图

实现代码
- 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);
}
}
- 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;
}
}
}
}
}
- 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
欢迎与我交流
- 打代码直播间:https://live.bilibili.com/11883038
- 微信公众号:DealiAxy
- 知乎:https://www.zhihu.com/people/dealiaxy
- 博客:https://blog.deali.cn
- 简书:https://www.jianshu.com/u/965b95853b9f
_EOF_
操作系统学习一:NetCore-实现模拟多道程序设计的简单处理机调用
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
操作系统学习三:进程调度与死锁-以及银行家算法避免死锁--NetCore实现
前言 这是操作系统学习的第三篇啦,关于进程调度有很多内容,操作系统在调度进程的时候最容易遇到的问题就是死锁了,银行家算法是一个典型的避免死锁算法。 死锁的概念 先来了解一下死锁的基本概念:一组竞争系统资源或相互通信的进程相互的“永久”阻塞。若无外力作用,这组进程将永远不能继续执行。 看下面两幅图片,左边是可能产生死锁的状态,四辆汽车(进程)要竞争同一个资源(通过路口),如果系统调度不当,就会陷入死
2021-12-18 · 计科基础 · 约 1 分钟
编译原理学习一,去除代码中的注释
前言 开始学习编译原理了耶~ 关于编译原理的所有练习,按照老规矩,还是用我最喜欢的C#语言来实现,运行在.NetCore平台上~ 关于这个系列的所有代码已经上传到github了,项目主页: https://github.com/Deali-Axy/CompilerConstructionLearning 本次题目 对C或C++等高级程序设计语言编写的源程序中的//注释和/…/注释进行删除,保留删除
2022-06-17 · 计科基础 · 约 1 分钟
设计模式之代理模式浅析
代理模式 在客户端与实体之间建立一个代理对象(proxy),客户端对实体进行操作全部委派给代理对象, 隐藏实体的具体实现细节。 Proxy还可以与业务代码分离,部署到另外的服务器。业务代码中通过RPC来委派任务。 代理模式与父类和接口的异同 相同点:代理模式的作用和父类以及接口和组合的作用类似,都是为了聚合共用部分,减少公共部分的代码 不同点: 相比起父类,他们的语境不同,父类要表达的含义是 is
2022-06-17 · 计科基础 · 约 1 分钟
操作系统学习二:进程同步与互斥之生产者-消费者问题--NetCore实现
目的 1. 掌握进程(线程)的同步与互斥。 2. 掌握生产者消费者问题的实现方法。 3. 掌握VC的多线程编程方法。 内容 本实验要求设计并实现一个进程,该进程拥有3个生产者线程和1个消费者线程,它们使用10个不同的缓冲区。需要使用如下信号量: 一个mutex信号量,用以阻止生产者线程和消费者线程同时操作缓冲区队列; 一个full信号量,当生产者线程生产出一个物品时可以用它向消费者线程发出信号;
2022-06-17 · 计科基础 · 约 1 分钟
讨论
共 0 条加载评论中…