第二次结对编程_电梯调度的可视化

第二次结对编程_电梯调度的可视化

10061130 殷鹏程

10061204 姚  铭

运行时截图

 

主要功能:

  1. 完整反映了电梯调度的整个过程
  2. 动态展示要求的与未要求的运行时数据

a)         当前运行时长

b)         当前活跃乘客数目

c)         所有乘客平均旅行时间

d)         当前乘客平均旅行时间(所有活跃乘客的平均旅行时间)

e)         乘客最长旅行时间(当前活跃乘客+已到达目的地乘客)

f)          已到达目的地乘客的最短旅行时间

g)         每层乘客等待人数

h)         每层的电梯指示灯

  1. UI自适应,动画展示电梯运行过程
  2. 支持点击电梯显示当前选中电梯的相关数据
  3. 运行\暂停\停止 控制功能

 

源程序架构

程序包括两个线程,UI线程与电梯调度算法所在的线程.

程序采用消息队列的形式,类MessageQueue以静态工厂化方式提供给每一个子项目(Passenger,Elevator,etc),对于电梯,乘客的每一次状态改变(电梯运行,乘客按键,乘客进入电梯),均将相应状态提交至消息队列,并由主类中的相关逻辑在同一线程,同一Ticks下完成消息的处理,并驱动UI线程的相关显示功能.

考虑到编码方便,电梯位置消息并未封装至消息队列中,而是直接使用窗体提供的委托化方法,已实现UI中电梯的运动.

 

代码行数(仅UI部分以及UI相关逻辑)

大于800行

 

设计心得

这次的结对编程,难点不在算法,而在于如何实现跨线程的数据传送与控件的控制,UI线程需要及时的显示调度线程的状态变化,调度线程在必要时需要直接驱动UI线程的显示.

在设计中,我们使用了消息队列的模式实现线程间的消息传送,使用代理(delegate)实现调度线程对UI线程的驱动.这样的设计编码成本低,且维护性较高.

在Console模式下的调度程序里,所有的状态都是直接打印到控制台的,只需要将控制台输出的语句替换为提交消息的语句:

/* Console.WriteLine("[Passenger] {0} is pressing, from {1} to {2}, ", 
                        _name, _SourceFloor, _TargetFloor);*/

MsgQueue.GetInstance().EnQueue(
     new Message(msg,this,MessageType.PassengerCome)
);

其中的MessageQueue类使用典型的静态工厂方法

public class MsgQueue
    {

        Queue<Message> msgQueue;
        static MsgQueue instance = null;
        static object lockObj = new object();

        private MsgQueue()
        {
            msgQueue = new Queue<Message>();
        }

        public static MsgQueue GetInstance()
        {
            lock (lockObj)
            {
                if (instance == null)
                {
                    instance = new MsgQueue();
                }
            }
            return instance;
        }

        public int Count { get { return msgQueue.Count; } }

        public void EnQueue(Message msg)
        {
            msgQueue.Enqueue(msg);
        }

        public Message DeQueue()
        {
            return msgQueue.Dequeue();
        }
    }

关于跨线程的UI驱动:

跨线程驱动使用了代理(delegate)的模式,在UI窗体类MainForm中,提供了公有方法:

public void SetWaitLb(int i, int num)
        {
            this.Invoke(new SetWaitLbDel(setWaitLb), new object[] { i, num });
        }

其中SetWaitLbDel为delegate,setWaitLb()为私有方法(实现UI控制逻辑)

此外,为了显示电梯运行时数据,需要进行一些数学运算,运算虽不复杂,但几乎都有涉及循环编译,为了简化编码,清一色采用Linq实现:

double actTotalTime = (from p in status.ActivePassengers select (ticks - p.DirectionReqTime)).Sum();
                double inactTotalTime = (from p in status.InActivePassengers select p.ReqCompleteTime - p.DirectionReqTime).Sum();
                status.AvgTravelTime = (actTotalTime+inactTotalTime)/status.PassengerNum;
                status.CurrentActTravelTime = actTotalTime / status.ActivePassengerNum;

                double maxActTime = 0;
                double minActTime = 0;
                double maxInActTime = 0;
                double minInActTime = 0; 
                try{
                    maxActTime = (from p in status.ActivePassengers select (ticks - p.DirectionReqTime)).Max();
                    minActTime  = (from p in status.ActivePassengers select (ticks - p.DirectionReqTime)).Min();
                    maxInActTime = (from p in status.InActivePassengers select p.ReqCompleteTime - p.DirectionReqTime).Max();
                    minInActTime = (from p in status.InActivePassengers select p.ReqCompleteTime - p.DirectionReqTime).Min();

                    MainForm.SetMaxTime(Math.Max(maxActTime, maxInActTime));
                    MainForm.SetMinTime(minInActTime);
                }
                catch { }

 

使用说明

1.点击“选择乘客xml”,选择一个乘客数据文件。

 

2.点击“选择电梯”,选择一个电梯数据文件。

 

3.在调度算法栏中,选择一个调度算法。

 

4.点击“运行”,程序开始启动。

 

左则显示了各个电梯所在楼层,箭头为绿色表示当前乘客的请求。

运行过程中,可以动态显示基本运行数据。

 

任意点击一个电梯,可以显示该电梯的具体数据。

 

同时,运行过程中可以随时暂停或停止。

 

 

posted @ 2013-01-09 22:36  yao9208  阅读(279)  评论(0编辑  收藏  举报