五种进程调度的算法实现(三)

实验要求

完成进程调度的可视化。

包括六种调度算法:

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;
        }
    }

运行结果

参见上一篇《五种进程调度的算法实现(二)》结尾处的测试图。

原文地址:https://www.cnblogs.com/bajdcc/p/4736380.html