[WCS 立库] 指令任务分解多线程实现,记录
过程方式写法很简单,为了维护性还是拆分了一个入库任务为多个子服务的形式。
起重机子服务任务:
private AutoResetEvent carneResetEvent; // 线程停止、启动信号量
private InComTaskQueue _inComTaskQueue; // 任务队列
private bool isSuccessed = false;
//这一步任务成功
public event Action SuccessEvent;// 初始化对象需要注册这个回调事件
public CarneService(AutoResetEvent autoResetEvent,InComTaskQueue inComTaskQueue,Action registerAction) {
carneResetEvent = autoResetEvent;
_inComTaskQueue = inComTaskQueue;
SuccessEvent += registerAction;
}
public Task TaskStart() {
return Task.Run(() => {
Console.WriteLine("起重机任务开始");
while (true) {
//进行等待
carneResetEvent.WaitOne();
var res = _inComTaskQueue.OutQueue();
// 发送plc指令到起重
var writePlc= SendCmdToMotor();
// send
// 不断发送读取PLC获取当前设备运行状态
while (true)
{
var askRes = AskCurrentCarneState();
if (askRes==10) {
// 第一步任务执行成功
break;
}
}
//触发通知
SuccessEvent();
// 完成后 起重机线程陷入阻塞状态
}
});
}
小车物料搬运者子任务:
private event Action CarSuccess; // 子任务完成后的回调事件
private InComeTaskModel _inComeTaskModel; // 具体任务模型
private AutoResetEvent CarResetEvent;// 线程中断恢复 信号量
public Task RunTask() {
return Task.Run(() => {
while (true)
{
CarResetEvent.WaitOne();
//任务开始
// 发出指令给小车
var zhuanghuoCmdRes = SendzhuanghuoCmd();
// 不断读取小车状态获取小车是否已经装货
while (true)
{
var zhuanghuoState = ReadIsZhuanghuo();
if (zhuanghuoState == 10)
{
break;
}
}
// 发送PLC指令 写入物料运送点位位置
SendTargetWeizhi();
// 不断读取小车运送状态
while (true)
{
var delRes = IsdeliverCurrentCount();
if (delRes == 10)
{
break;
}
}
// 小车运送完成后 触发当前的success事件
CarSuccess();
// 当前任务执行线程 陷入阻塞
}
});
}
两个重要角色的任务起重机和小车任务定义完毕,采用AutoResetEvent方式,让出线程调度。
while死循环判断任务是否进行会暂用大量CPU资源,而且会产生内存屏障的脏读现象。
内部while就不管了,因为跟PLC或者西门子的设备交互都是很傻的被动形式。估计这种工业级硬件通讯也不可能增加主动通知功能了。
应用入口函数中调用:
Task.Run(() => {
CarneService carneService = new CarneService(CarneEvent, inComTaskQueue, () => {
Console.WriteLine("起重机任务结束");
CarResetEvent.Set();// 起重机完成后,打开小车执行开关
});
CarService carService = new CarService(CarResetEvent, () => {
Console.WriteLine("小车任务执行完成");
isSuccess = true;
});
var t = carneService.TaskStart();
var t1 = carService.RunTask();
while (true) { // 这里也可以换成 autoresetEvent 控制线程方式.
if (inComTaskQueue.InComeTaskModels.Count<=0) {
continue;
}
CarneEvent.Set();// 打开开关
}
});
WCS的入库工单其实是需要从WMS系统中获取。这里只是做一个集合的模拟。
获取任务对象后,才会真正执行具体任务内容。
WCS一个入库或者出库任务 具体执行起来都是必须具备执行顺序:
我这里是 起重机先执行 后执行小车搬运任务,然后执行其他任务。
当然每个立库项目内容不一样,就可以灵活变动,通过打开以及关闭线程信号量来决定。
然后每个·子任务线程是不结束状态。这个类似java的notify方式。c# 我感觉更加灵活,事件触发方式更加舒服。
完整项目通过AutoFac的依赖注入形式,就可以再任务类中注入日志 数据库 其他协议(ModbusTCP\modbusRTU \S7等协议实现),有一定的业务解耦性。