《数据结构、算法与应用 —— C++语言描述》学习笔记 — 队列 —— 应用 —— 工厂仿真(一)

本文是《数据结构、算法与应用 —— C++语言描述》的学习笔记,通过C++实现了一个工厂仿真实例,探讨了如何使用队列模拟任务调度,观察者模式用于机器状态变化的跟踪,以及工厂仿真的好处,包括瓶颈分析和决策支持。
摘要由CSDN通过智能技术生成

一、问题描述

一个工厂有m台机器。工厂的每项任务都需要若干道工序才能完成。每台机器都执行一道工序,不同的机器执行不同的工序。一台机器一旦开始执行一道工序就不会中断,直到该工序完成为止。

每道工序都需要 工序时间 和执行该工序的机器。一项任务中的若干道工序必须按照一定顺序来完成。一项任务首先被调度到执行其第一道工序的机器上;当第一道工序完成后,该任务被转到执行第二道工序的机器上;依次进行下去,直到该任务的最后一道工序完成为止。当一项任务到达一台机器时,可能机器正忙,因此要等待。事实上,很可能有若干项任务同时在一台机器旁等待。

每台机器都有如下三种状态:活动状态、空闲状态和转换状态。在活动状态,机器正在执行一道工序;在空闲状态,机器无事可做;在转换状态,机器刚刚完成一道工序,并准备执行一道新工序。在转换状态,机器操作员可能需要清理机器,把刚刚使用的工具放好,然后稍作休息。每台机器在转换状态所花费的时间多少因机器而定。

当一台机器执行一项新任务时,他需要从等待执行的任务中选择一项任务。我们假设没他机器都按照 FIFO 的方式来选择,因此在每台机器旁等待执行的任务构成一个队列。也可以假设其他的选择方式。例如,根据任务的优先级来选择。每项任务都有一个优先级,当机器空闲时,等待执行的任务中优先级最高的任务被优先执行。

一项任务的最后一道工序的完成时间称为该任务的 完成时间。一项任务的 长度 等于其所有工序时间之和。如果一项长度为 l 的任务在0时刻到达工厂,在 f 时刻完成,那么它在机器队列中的等待时间恰好为 f − l f-l fl。为了让顾客满意,我们要尽量减少任务的等待时间。如果知道任务的等待时间是多少,而且知道在哪些机器旁等待的时间醉倒,我们就可以改进和提高工厂的效率。

二、如何仿真

与书中提供的方式不同,我们这里尝试借此应用练习观察者模式。在主过程中,我们模拟时间的增加,以触发机器状态的改变。我们为机器类提供一个抽象的观察者,任务的调度以及静态数据的统计各自实现一个观察者。当机器状态发生改变或有任务被放到机器的任务队列中时,会通知这些观察者。

三、工厂仿真的例子

考察一个工厂,它有3台机器,有6项任务。假设这些任务都在0时刻出现,而且在仿真期间不再有新的任务。仿真过程一直持续到所有任务完成为止。
三台机器为M1、M2、M3,它们的转换状态所花费的时间分别为2、0、1。因此,当一道工序完成时,机器M1必须等待2个时间单元才能启动下一个任务,机器M2不需要等待即可开始下一个任务,机器M3必须等待1个时间单元才能启动下一个任务。各任务所需的机器及对应的时间如下:
在这里插入图片描述
任务执行过程中各机器状态表如下图,其中,I — 空闲,C — 转换,E — 执行(数字为任务编号):
在这里插入图片描述
任务执行过程中各机器上的任务队列情况如图:
在这里插入图片描述
任务的完成时间和等待时间如下图:
在这里插入图片描述

四、工厂仿真的好处

1、通过仿真,可以发现工场中的瓶颈。如果瓶颈是油漆工段,局可以补强油漆工段。类似地,如果瓶颈是钻孔等待时间过长,就可以调配更多的钻孔操作员和钻孔机器。所以,仿真可以用于短期运行调度决策。
2、使用工厂仿真器,我们可以回答这样的问题:如果用一台投资更多但效果更好的机器替代一台现有的机器,平均等待时间是否可以减少?因此,仿真可以在工厂的扩展/现代化过程中帮助决策。
3、当客户想估计任务完成的准确时间时,可以通过工厂仿真器得到。

五、设计

类图为:
在这里插入图片描述
目录结构为:

[factorySimulation]
	test.h
	[document]
	[output]
	[src]
		[data]
			CLS_DataManager.h
			CLS_DataManager.cpp
			[job]
				CLS_Job.h
				CLS_Job.cpp
			[machine]
				CLS_Machine.h
				CLS_Machine.cpp
				CLS_MachineObserver.h
				CLS_MachineObserver.cpp
		[service]
			CLS_DispatchManager.h
			CLS_DispatchManager.cpp
			CLS_Statistics.h
			CLS_Statistics.cpp

这个应用我集成在我自己的vs项目中,所以没有工程文件和 main.cpp

六、工序和任务

1、声明

/*************************************************
Author: coding-hwz
Date:2021-08-23
Description: 提供工序和任务结构体,用于任务中工序FIFO方式的增、删、查
**************************************************/

#pragma once
#include <queue>
#include <optional>

// 工序结构体
struct CLS_Task
{
   
    int m_iMachineId = 0;	// 该工序所需要机器编号
    int m_iTime = 0;	    // 该工序所需要时间
};

// 任务结构体
class CLS_Job
{
   
public:
    CLS_Job(int _iJobId);

    /*
     * @brief 添加一道工序
     * @param _iMachine 机器编号
     * @param _iTime    工序时长
     */
    void addTask(int _iMachine, int _iTime);

    /*
     * @brief 移除下一道工序
     */
    void removeNextTask();

    /*
     * @brief 获得下一道工序
     * @return 工序 optional 对象
     */
    std::optional<struct CLS_Task> getNextTask();

    /*
     * @brief 获得任务编号
     * @return 任务编号
     */
    int getJobId() const;

private:
    std::queue<CLS_Task> m_queueTasks;  // 任务列表
    int m_iJobId;                       // 任务编号
};

2、实现

#include "CLS_Job.h"
using namespace std;

CLS_Job::CLS_Job(int _iJobId)
{
   
    m_iJobId = _iJobId;
}

void CLS_Job::addTask(int _iMachine, int _iTime)
{
   
    m_queueTasks.push({
    _iMachine, _iTime });
}

void CLS_Job::removeNextTask()
{
   
    if (m_queueTasks.empty())
    {
   
        throw exception("task list is empty");
    }

    m_queueTasks.pop();
}

optional<struct CLS_Task> CLS_Job::getNextTask()
{
   
    if (m_queueTasks.empty())
    {
   
        return nullopt;
    }

    return m_queueTasks.front();
}

int CLS_Job::getJobId() const
{
   
    return m_iJobId;
}

七、机器观察者

1、声明


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值