實驗要求
完成進程調度的可視化。
包括六種調度算法:
public enum SchdType { [Description("先來先服務")] FCFS, [Description("最短作業優先")] SJF, [Description("最短剩余時間優先")] SRTF, [Description("最高響應比優先")] HRRF, [Description("優先級調度")] PRIOR, [Description("輪轉調度")] RR, }
設計思路
使用C# WindowsForm易於開發。
- 調度算法基於LINQ;
- 所有調度算法采用統一的接口;
- 用DataGridView呈現和更改初始數據;
- 用GDI+實現繪圖。
數據結構
初始數據結構:
public class SimpleTask { [Unique] [DefaultValue("Task")] [Description("作業名")] public string Name { set; get; } [DefaultValue(0)] [Description("開始時間")] public int StartTime { set; get; } [DefaultValue(1)] [Description("運行時間")] public int ExecuteTime { set; get; } [DefaultValue(0)] [Description("優先級")] public int Priority { set; get; } }
初始化:
void InitTestData() { data.Rows.Add(new object[] { "A", 0, 3, 5 }); data.Rows.Add(new object[] { "B", 2, 6, 2 }); data.Rows.Add(new object[] { "C", 4, 4, 3 }); data.Rows.Add(new object[] { "D", 6, 5, 4 }); data.Rows.Add(new object[] { "E", 8, 2, 1 }); }
運行時調度結構:
public class SchdRestModel { public SimpleTask task { set; get; } public int rest { set; get; }//剩余運行時間 public double temp { set; get; }//用於存儲響應比 }
輸入輸出結構:
public class SimulationResult { public List<SimpleTask> tasks { set; get; } public List<string> cpu_clips { set; get; } }
可視化結構:
public class VisualStruct { public DuringStruct during { set; get; } public List<Tuple<int, int>> cpu_clips { set; get; } } public class VisualData { public Dictionary<string, VisualStruct> visual { set; get; } public List<int> switches { set; get; } }
參數設置:
public class SchdSettings { private static int _TimeSpan = 1; public static int TimeSpan { set { _TimeSpan = value; } get { return _TimeSpan; } } public static readonly int MaxTimeSpan = 10; public static readonly int MinTimeSpan = 1; } public class VisualSettings { public static readonly int TimeSpanWidth = 30; public static readonly int TaskHeight = 30; public static readonly int TaskSpacing = 20; public static readonly int TaskBlanking = 20; public static readonly int TimeHeight = 20; public static readonly int DegreeHeight = 5; public static readonly int DispTextWidth = 100; public static readonly int Margin = 5; }
設計實現
一、接口及抽象類
調度接口:
public interface IProcessSchd { void ImportData(IEnumerable<SimpleTask> tasks); void SetCallback(Action<string> action); SimulationResult Simulate(); }
抽象基類:
public abstract class ProcessSchd : IProcessSchd { protected IEnumerable<SimpleTask> origin_tasks; protected Action<string> action; public void ImportData(IEnumerable<SimpleTask> tasks) { origin_tasks = tasks; } public void SetCallback(Action<string> action) { this.action = action; } public abstract SimulationResult Simulate(); }
工廠模式構建:
public class SchdFactory { static public IProcessSchd CreateSchdInstance(SchdType type) { return Assembly.GetExecutingAssembly().CreateInstance("SimuProcessSchd.Schd" + type.ToString()) as IProcessSchd; } }
二、通用算法
2.1 通用算法版本一(適用於除輪轉調度以外的五種調度算法)
/// <summary> /// 通用調度算法版本一 /// </summary> /// <param name="task">運行時處理隊列</param> /// <param name="blocked">是否獨占式調度(非剝奪)</param> /// <param name="select">自定義任務競取函數</param> /// <returns></returns> static public List<string> GetSimuResultDirectV1(IEnumerable<SchdRestModel> task, bool blocked, Func<IEnumerable<SchdRestModel>, int, IEnumerable<SchdRestModel>> select) { var list = new List<string>();//用於存放結果 var new_list = task.ToList();//當前任務隊列的拷貝,用於調度 IEnumerable<SchdRestModel> selected = null; for (int i = 0; new_list.Count() > 0; i++)//進行運行時調度,當前隊列為空時結束 { //當規定為可剝奪時,初始化任務競取函數,用於選取下一任務 if (!blocked || (blocked && selected == null)) selected = select(new_list, i); if (selected.Count() > 0)//可以選取下一任務 { var running = selected.First();//取下一任務隊列頭 list.Add(running.task.Name);//當前時刻處理該任務並記錄任務名 if (running.rest > 1)//當前任務還有剩余運行時間 { //當前運行的任務的剩余時間減一 new_list.Find(a => a.task.Name == running.task.Name).rest--; } else//當前任務已完成 { if (selected != null) selected = null;//清空競取函數 //從調度隊列中除去該任務 new_list.RemoveAll(a => a.task.Name == running.task.Name); } } else//已經沒有任務可選取,收尾工作 { if (selected != null) selected = null; list.Add(null); } } return list; }
2.2 通用算法版本二(只適用於輪轉調度)
/// <summary> /// 通用調度算法版本二 /// </summary> /// <param name="task">起始的任務隊列</param> /// <returns>模擬調度結果</returns> static public List<string> GetSimuResultDirectV2(IEnumerable<SchdRestModel> task) { var list = new List<string>(); //采用雙隊列,后備和輪轉 var backup = task.ToList(); // 后備隊列 var round = new List<SchdRestModel>(); // 輪轉隊列 //當雙隊列都不為空時,繼續運行,i為時刻 for (int i = 0; backup.Count > 0 || round.Count > 0; i++) { SchdRestModel current = null; // 檢查后備 if (round.Count == 0)//當前輪轉隊列為空時,取后備隊列 { round.AddRange( from x in backup where x.task.StartTime <= i orderby x.task.StartTime//按起始時間 orderby x.task.Priority//按優先級 select x); backup.RemoveAll(a => a.task.StartTime <= i);//做移動操作,將舊的刪除 } // 處理輪轉 if (round.Count > 0)//輪轉不為空,則有任務 { current = round.First();//取隊列頭 round.RemoveAt(0);//清除 } // 取出隊頭並處理 if (current != null) { var min = Math.Min(current.rest, SchdSettings.TimeSpan);//輪轉時獨占時長的限制 current.rest -= min;//減去當前運行時間 for (int j = 0; j < min; j++) { list.Add(current.task.Name);//添加運行記錄 } if (current.rest <= 0) { current = null;//沒有剩余時間則丟棄 } i += min - 1;//時刻表推進,由於for循環對i有自增操作,所以這里減一 } else { list.Add(null);//結束標記 } // 再次處理后備 { round.AddRange( from x in backup where x.task.StartTime <= i + 1 orderby x.task.StartTime orderby x.task.Priority select x); backup.RemoveAll(a => a.task.StartTime <= i + 1); } // 將當前任務放至隊尾 if (current != null) { round.Add(current); } } return list; }
三、具體算法
/// <summary> /// 先來先服務 /// </summary> public class SchdFCFS : ProcessSchd { public override SimulationResult Simulate() { var result = new SimulationResult() { tasks = origin_tasks.ToList() }; result.cpu_clips = SchdImplHelper.GetSimuResultDirectV1( from x in origin_tasks orderby x.StartTime select new SchdRestModel { task = x, rest = x.ExecuteTime, }, true, (a, i) => from x in a where x.task.StartTime <= i select x ); return result; } } /// <summary> /// 最短作業優先 /// </summary> public class SchdSJF : ProcessSchd { public override SimulationResult Simulate() { var result = new SimulationResult() { tasks = origin_tasks.ToList() }; result.cpu_clips = SchdImplHelper.GetSimuResultDirectV1( from x in origin_tasks orderby x.StartTime select new SchdRestModel { task = x, rest = x.ExecuteTime, }, true, (a, i) => from x in a where x.task.StartTime <= i orderby x.task.ExecuteTime select x ); return result; } } /// <summary> /// 最短剩余時間優先 /// </summary> public class SchdSRTF : ProcessSchd { public override SimulationResult Simulate() { var result = new SimulationResult() { tasks = origin_tasks.ToList() }; result.cpu_clips = SchdImplHelper.GetSimuResultDirectV1( from x in origin_tasks orderby x.ExecuteTime select new SchdRestModel { task = x, rest = x.ExecuteTime, }, false, (a, i) => from x in a where x.task.StartTime <= i orderby x.rest select x ); return result; } } /// <summary> /// 最高響應比優先 /// </summary> public class SchdHRRF : ProcessSchd { public override SimulationResult Simulate() { var result = new SimulationResult() { tasks = origin_tasks.ToList() }; result.cpu_clips = SchdImplHelper.GetSimuResultDirectV1( from x in origin_tasks orderby x.StartTime select new SchdRestModel { task = x, rest = x.ExecuteTime, }, true, (a, i) => from y in (from x in a where x.task.StartTime <= i select new SchdRestModel { task = x.task, rest = x.rest, temp = ((double)i - (double)x.task.StartTime) / (double)x.task.ExecuteTime }) orderby y.temp descending select y ); return result; } } public class SchdPRIOR : ProcessSchd { public override SimulationResult Simulate() { var result = new SimulationResult() { tasks = origin_tasks.ToList() }; result.cpu_clips = SchdImplHelper.GetSimuResultDirectV1( from x in origin_tasks orderby x.StartTime select new SchdRestModel { task = x, rest = x.ExecuteTime, }, false, (a, i) => (from x in a where x.task.StartTime <= i orderby x.task.Priority select x) ); return result; } } public class SchdRR : ProcessSchd { public override SimulationResult Simulate() { var result = new SimulationResult() { tasks = origin_tasks.ToList() }; result.cpu_clips = SchdImplHelper.GetSimuResultDirectV2( from x in origin_tasks select new SchdRestModel { task = x, rest = x.ExecuteTime, }); return result; } }
