[WCS 立庫(kù)] 指令任務(wù)分解多線(xiàn)程實(shí)現(xiàn),記錄
過(guò)程方式寫(xiě)法很簡(jiǎn)單,為了維護(hù)性還是拆分了一個(gè)入庫(kù)任務(wù)為多個(gè)子服務(wù)的形式。
起重機(jī)子服務(wù)任務(wù):
? private AutoResetEvent carneResetEvent; // 線(xiàn)程停止、啟動(dòng)信號(hào)量
? ? ? ? private InComTaskQueue _inComTaskQueue; // 任務(wù)隊(duì)列
? ? ? ? private bool isSuccessed = false;
? ? ? ? //這一步任務(wù)成功
? ? ? ? public event Action SuccessEvent;//?初始化對(duì)象需要注冊(cè)這個(gè)回調(diào)事件
? ? ? ? public CarneService(AutoResetEvent autoResetEvent,InComTaskQueue inComTaskQueue,Action registerAction) {
? ? ? ? ? ? carneResetEvent = autoResetEvent;
? ? ? ? ? ? _inComTaskQueue = inComTaskQueue;
? ? ? ? ? ? SuccessEvent += registerAction;
? ? ? ? }
?public Task TaskStart() {
? ? ? ? ? ? return Task.Run(() => {
? ? ? ? ? ? ? ? Console.WriteLine("起重機(jī)任務(wù)開(kāi)始");
? ? ? ? ? ? ? ? while (true) {
? ? ? ? ? ? ? ? ? ? //進(jìn)行等待
? ? ? ? ? ? ? ? ? ? carneResetEvent.WaitOne();
? ? ? ? ? ? ? ? ? ? var res = _inComTaskQueue.OutQueue();
? ? ? ? ? ? ? ? ? ? // 發(fā)送plc指令到起重
? ? ? ? ? ? ? ? ? ? var writePlc= SendCmdToMotor();
? ? ? ? ? ? ? ? ? ? // send?
? ? ? ? ? ? ? ? ? ? // 不斷發(fā)送讀取PLC獲取當(dāng)前設(shè)備運(yùn)行狀態(tài)
? ? ? ? ? ? ? ? ? ? while (true)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? var askRes = AskCurrentCarneState();
? ? ? ? ? ? ? ? ? ? ? ? if (askRes==10) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 第一步任務(wù)執(zhí)行成功
? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? //觸發(fā)通知
? ? ? ? ? ? ? ? ? ? SuccessEvent();
? ? ? ? ? ? ? ? ? ? // 完成后 起重機(jī)線(xiàn)程陷入阻塞狀態(tài)
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
小車(chē)物料搬運(yùn)者子任務(wù):
private event Action CarSuccess; // 子任務(wù)完成后的回調(diào)事件
? ? ? ? private InComeTaskModel _inComeTaskModel; // 具體任務(wù)模型
? ? ? ? private AutoResetEvent CarResetEvent;// 線(xiàn)程中斷恢復(fù) 信號(hào)量
?public Task RunTask() {
? ? ? ? ? ? return Task.Run(() => {
? ? ? ? ? ? ? ? while (true)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? CarResetEvent.WaitOne();
? ? ? ? ? ? ? ? ? ? //任務(wù)開(kāi)始
? ? ? ? ? ? ? ? ? ? // 發(fā)出指令給小車(chē)
? ? ? ? ? ? ? ? ? ? var zhuanghuoCmdRes = SendzhuanghuoCmd();
? ? ? ? ? ? ? ? ? ? // 不斷讀取小車(chē)狀態(tài)獲取小車(chē)是否已經(jīng)裝貨
? ? ? ? ? ? ? ? ? ? while (true)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? var zhuanghuoState = ReadIsZhuanghuo();
? ? ? ? ? ? ? ? ? ? ? ? if (zhuanghuoState == 10)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? // 發(fā)送PLC指令 寫(xiě)入物料運(yùn)送點(diǎn)位位置?
? ? ? ? ? ? ? ? ? ? SendTargetWeizhi();
? ? ? ? ? ? ? ? ? ? // 不斷讀取小車(chē)運(yùn)送狀態(tài)?
? ? ? ? ? ? ? ? ? ? while (true)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? var delRes = IsdeliverCurrentCount();
? ? ? ? ? ? ? ? ? ? ? ? if (delRes == 10)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? // 小車(chē)運(yùn)送完成后 觸發(fā)當(dāng)前的success事件?
? ? ? ? ? ? ? ? ? ? CarSuccess();
? ? ? ? ? ? ? ? ? ? // 當(dāng)前任務(wù)執(zhí)行線(xiàn)程 陷入阻塞
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? ? ??
? ? ? ? }
兩個(gè)重要角色的任務(wù)起重機(jī)和小車(chē)任務(wù)定義完畢,采用AutoResetEvent方式,讓出線(xiàn)程調(diào)度。
while死循環(huán)判斷任務(wù)是否進(jìn)行會(huì)暫用大量CPU資源,而且會(huì)產(chǎn)生內(nèi)存屏障的臟讀現(xiàn)象。
內(nèi)部while就不管了,因?yàn)楦鶳LC或者西門(mén)子的設(shè)備交互都是很傻的被動(dòng)形式。估計(jì)這種工業(yè)級(jí)硬件通訊也不可能增加主動(dòng)通知功能了。
應(yīng)用入口函數(shù)中調(diào)用:
?Task.Run(() => {
? ? ? ? ? ? ? ? CarneService carneService = new CarneService(CarneEvent, inComTaskQueue, () => {
? ? ? ? ? ? ? ? ? ? Console.WriteLine("起重機(jī)任務(wù)結(jié)束");
? ? ? ? ? ? ? ? ? ? CarResetEvent.Set();// 起重機(jī)完成后,打開(kāi)小車(chē)執(zhí)行開(kāi)關(guān)
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? CarService carService = new CarService(CarResetEvent, () => {
? ? ? ? ? ? ? ? ? ? Console.WriteLine("小車(chē)任務(wù)執(zhí)行完成");
? ? ? ? ? ? ? ? ? ? isSuccess = true;
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? var t = carneService.TaskStart();
? ? ? ? ? ? ? ? var t1 = carService.RunTask();
? ? ? ? ? ? ? ? while (true) { // 這里也可以換成 autoresetEvent 控制線(xiàn)程方式.
? ? ? ? ? ? ? ? ? ? if (inComTaskQueue.InComeTaskModels.Count<=0) {
? ? ? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? CarneEvent.Set();// 打開(kāi)開(kāi)關(guān)
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
WCS的入庫(kù)工單其實(shí)是需要從WMS系統(tǒng)中獲取。這里只是做一個(gè)集合的模擬。
獲取任務(wù)對(duì)象后,才會(huì)真正執(zhí)行具體任務(wù)內(nèi)容。
WCS一個(gè)入庫(kù)或者出庫(kù)任務(wù) 具體執(zhí)行起來(lái)都是必須具備執(zhí)行順序:
我這里是 起重機(jī)先執(zhí)行 后執(zhí)行小車(chē)搬運(yùn)任務(wù),然后執(zhí)行其他任務(wù)。
當(dāng)然每個(gè)立庫(kù)項(xiàng)目?jī)?nèi)容不一樣,就可以靈活變動(dòng),通過(guò)打開(kāi)以及關(guān)閉線(xiàn)程信號(hào)量來(lái)決定。
然后每個(gè)·子任務(wù)線(xiàn)程是不結(jié)束狀態(tài)。這個(gè)類(lèi)似java的notify方式。c# 我感覺(jué)更加靈活,事件觸發(fā)方式更加舒服。
完整項(xiàng)目通過(guò)AutoFac的依賴(lài)注入形式,就可以再任務(wù)類(lèi)中注入日志 數(shù)據(jù)庫(kù) 其他協(xié)議(ModbusTCP\modbusRTU \S7等協(xié)議實(shí)現(xiàn)),有一定的業(yè)務(wù)解耦性。