From a46d0b526dfb595d4cea40b9a87934697c0ae1e3 Mon Sep 17 00:00:00 2001 From: backuppc Date: Tue, 18 Nov 2025 08:52:11 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9E=A5=EC=B9=98=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=9D=84=20=EB=B3=84=EB=8F=84=20=EC=93=B0?= =?UTF-8?q?=EB=A0=88=EB=93=9C=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 상태머신에서 장치 연결(AGV, XBee, BMS)이 메인 루프를 블로킹하는 문제 해결 주요 변경사항: - DeviceConnectionWorker: 별도 쓰레드에서 장치 연결 처리 - StartDeviceConnectionThread: 쓰레드 시작 로직 - StopDeviceConnectionThread: 프로그램 종료 시 안전한 쓰레드 종료 - sm_SPS: 연결 로직 제거, 쓰레드 시작만 담당 - __Closing: 프로그램 종료 시 쓰레드 종료 호출 이점: - 장치 연결 중 상태머신 블로킹 방지 - 1초 간격으로 비동기 연결 시도 - 프로그램 종료 시 안전한 쓰레드 정리 파일: - StateMachine/_SPS.cs: 쓰레드 로직 추가 - fMain.cs: 종료 시 쓰레드 정리 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Cs_HMI/Project/StateMachine/_SPS.cs | 126 ++++++++++++++++++++-------- Cs_HMI/Project/fMain.cs | 3 + 2 files changed, 96 insertions(+), 33 deletions(-) diff --git a/Cs_HMI/Project/StateMachine/_SPS.cs b/Cs_HMI/Project/StateMachine/_SPS.cs index 1f68f56..310746b 100644 --- a/Cs_HMI/Project/StateMachine/_SPS.cs +++ b/Cs_HMI/Project/StateMachine/_SPS.cs @@ -4,6 +4,7 @@ using System.Data; using System.Drawing; using System.Linq; using System.Text; +using System.Threading; using System.Windows.Media.Animation; using AR; using arCtl; @@ -18,6 +19,10 @@ namespace Project DateTime chargesynctime = DateTime.Now; DateTime agvsendstarttime = DateTime.Now; + // 장치 연결 쓰레드 관련 + private Thread deviceConnectionThread; + private volatile bool isDeviceConnectionRunning = false; + void ConnectSerialPort(arDev.arRS232 dev, string port, int baud, eVarTime conn, eVarTime conntry, eVarTime recvtime) { if (dev.IsOpen == false && port.isEmpty() == false) @@ -95,45 +100,100 @@ namespace Project } } + // 장치 연결 쓰레드 시작 + private void StartDeviceConnectionThread() + { + if (deviceConnectionThread == null || !deviceConnectionThread.IsAlive) + { + isDeviceConnectionRunning = true; + deviceConnectionThread = new Thread(DeviceConnectionWorker); + deviceConnectionThread.IsBackground = true; + deviceConnectionThread.Name = "DeviceConnectionThread"; + deviceConnectionThread.Start(); + PUB.log.Add("DeviceConnection", "장치 연결 쓰레드 시작"); + } + } + + // 장치 연결 쓰레드 종료 + private void StopDeviceConnectionThread() + { + if (deviceConnectionThread != null && deviceConnectionThread.IsAlive) + { + isDeviceConnectionRunning = false; + if (!deviceConnectionThread.Join(2000)) // 2초 대기 + { + try + { + deviceConnectionThread.Abort(); + } + catch { } + } + PUB.log.Add("DeviceConnection", "장치 연결 쓰레드 종료"); + } + } + + // 장치 연결 처리 워커 (별도 쓰레드에서 실행) + private void DeviceConnectionWorker() + { + while (isDeviceConnectionRunning) + { + try + { + if (PUB.sm.Step >= eSMStep.IDLE && PUB.sm.Step < eSMStep.CLOSING) + { + //agv connect + ConnectSerialPort(PUB.AGV, PUB.setting.Port_AGV, PUB.setting.Baud_AGV, + eVarTime.LastConn_AGV, eVarTime.LastConnTry_AGV, eVarTime.LastRecv_AGV); + + //xbee connect + ConnectSerialPort(PUB.XBE, PUB.setting.Port_XBE, PUB.setting.Baud_XBE, + eVarTime.LastConn_XBE, eVarTime.LastConnTry_XBE, eVarTime.LastRecv_XBE); + + //bms connect + if (PUB.BMS.IsOpen == false) + { + var ts = VAR.TIME.RUN(eVarTime.LastConn_BAT); + if (ts.TotalSeconds > 3) + { + Console.WriteLine($"bms connect to {PUB.setting.Port_BAT}"); + PUB.BMS.PortName = PUB.setting.Port_BAT; + PUB.BMS.Open(); + + VAR.TIME.Update(eVarTime.LastConn_BAT); + VAR.TIME.Update(eVarTime.LastConnTry_BAT); + } + } + else if (PUB.BMS.IsValid == false) + { + var ts = VAR.TIME.RUN(eVarTime.LastConnTry_BAT); + if (ts.TotalSeconds > 10) + { + Console.WriteLine("bms auto disconnect"); + PUB.BMS.Close(); + VAR.TIME.Set(eVarTime.LastConn_BAT, DateTime.Now.AddSeconds(5)); + } + } + } + } + catch (Exception ex) + { + PUB.log.AddE($"DeviceConnection: {ex.Message}"); + } + + // 1초 대기 후 다시 체크 + Thread.Sleep(1000); + } + } + void sm_SPS(object sender, EventArgs e) { if (PUB.sm.Step < eSMStep.IDLE || PUB.sm.Step >= eSMStep.CLOSING) return; - - //agv connect - ConnectSerialPort(PUB.AGV, PUB.setting.Port_AGV, PUB.setting.Baud_AGV, - eVarTime.LastConn_AGV, eVarTime.LastConnTry_AGV, eVarTime.LastRecv_AGV); - - //xbee connect - ConnectSerialPort(PUB.XBE, PUB.setting.Port_XBE, PUB.setting.Baud_XBE, - eVarTime.LastConn_XBE, eVarTime.LastConnTry_XBE, eVarTime.LastRecv_XBE); - - //bms connect - if (PUB.BMS.IsOpen == false) + // 장치 연결 쓰레드가 실행 중이 아니면 시작 + if (!isDeviceConnectionRunning) { - var ts = VAR.TIME.RUN(eVarTime.LastConn_BAT); - if (ts.TotalSeconds > 3) - { - Console.WriteLine($"bms connect to {PUB.setting.Port_BAT}"); - PUB.BMS.PortName = PUB.setting.Port_BAT; - PUB.BMS.Open(); - - VAR.TIME.Update(eVarTime.LastConn_BAT); - VAR.TIME.Update(eVarTime.LastConnTry_BAT); - } + StartDeviceConnectionThread(); } - else if (PUB.BMS.IsValid == false) - { - var ts = VAR.TIME.RUN(eVarTime.LastConnTry_BAT); - if (ts.TotalSeconds > 10) - { - Console.WriteLine("bms auto disconnect"); - PUB.BMS.Close(); - VAR.TIME.Set(eVarTime.LastConn_BAT,DateTime.Now.AddSeconds(5)); - } - } - //ConnectSerialPort(PUB.BMS, PUB.setting.Port_BAT, PUB.setting.Baud_BAT, - // eVarTime.LastConn_BAT, eVarTime.LastConnTry_BAT, eVarTime.LastRecv_BAT); //지그비상태전송 if (PUB.XBE != null && PUB.XBE.IsOpen) diff --git a/Cs_HMI/Project/fMain.cs b/Cs_HMI/Project/fMain.cs index 89c129c..70e3be9 100644 --- a/Cs_HMI/Project/fMain.cs +++ b/Cs_HMI/Project/fMain.cs @@ -110,6 +110,9 @@ namespace Project private void __Closing(object sender, FormClosingEventArgs e) { + // 장치 연결 쓰레드 종료 + StopDeviceConnectionThread(); + PUB.popup.needClose = true; if (remoteClose == true) {