Fix: 상태머신 루프 블로킹 문제 수정 - SPS 이벤트 핸들러 비동기 처리 및 타임아웃 보호 추가

- sm_SPS 이벤트 핸들러에서 장치 연결 및 상태 전송을 비동기로 처리

- DeviceConnectionWorker 스레드로 장치 연결 분리

- SPS(1초), Running(2초) 타임아웃 보호 추가

- 상태머신 모니터링 디버그 창 추가 (fStateMachineDebug)

- F11/F12 단축키로 스레드 덤프 및 디버그 브레이크 지원

- RaiseMessage 이벤트 비동기 처리로 로그 블로킹 방지
This commit is contained in:
backuppc
2025-12-04 14:43:57 +09:00
parent a46d0b526d
commit 34ad1db0e3
8 changed files with 1557 additions and 45 deletions

View File

@@ -87,18 +87,64 @@ namespace Project.StateMachine
private Boolean _isthreadrun;
public Boolean IsThreadRun { get { return _isthreadrun; } }
public int LoopCount { get { return _loopCount; } }
public DateTime LastLoopTime { get { return _lastLoopTime; } }
private int _loopCount = 0;
private DateTime _lastLoopTime = DateTime.Now;
void Loop()
{
_isthreadrun = true;
if (GetMsgOpt(EMsgOpt.NORMAL)) RaiseMessage("SM", "Start");
while (bLoop)
try
{
RunSpeed = DateTime.Now - UpdateTime; //이전업데이트에서 현재 시간의 오차 한바퀴 시간이 표시됨
UpdateTime = DateTime.Now;
while (bLoop)
{
_loopCount++;
_lastLoopTime = DateTime.Now;
// 루프 동작 확인용 로그 (10초마다)
if (_loopCount % 10000 == 0)
{
RaiseMessage("SM-LOOP", $"Loop alive - Count:{_loopCount}, bLoop:{bLoop}, Step:{Step}");
}
RunSpeed = DateTime.Now - UpdateTime; //이전업데이트에서 현재 시간의 오차 한바퀴 시간이 표시됨
UpdateTime = DateTime.Now;
//항상 작동하는 경우
SPS?.Invoke(this, new EventArgs());
try
{
var spsHandler = SPS;
if (spsHandler != null)
{
var spsStartTime = DateTime.Now;
var spsTask = System.Threading.Tasks.Task.Run(() =>
{
try
{
spsHandler(this, new EventArgs());
}
catch (Exception ex)
{
RaiseMessage("SM-ERROR-SPS", $"SPS Exception: {ex.Message}\n{ex.StackTrace}");
}
});
// 타임아웃 1초
if (!spsTask.Wait(1000))
{
var elapsed = (DateTime.Now - spsStartTime).TotalSeconds;
RaiseMessage("SM-TIMEOUT", $"SPS 이벤트 타임아웃 ({elapsed:F2}초 초과) - Step:{Step}");
}
}
}
catch (Exception ex)
{
RaiseMessage("SM-ERROR-SPS", $"SPS Exception: {ex.Message}\n{ex.StackTrace}");
}
//작동스텝이 변경되었다면 그것을 알림 처리한다.
if (GetNewStep != Step)
@@ -118,22 +164,47 @@ namespace Project.StateMachine
//동작중에 발생하는 이벤트
if (Running != null)
var runningHandler = Running;
if (runningHandler != null)
{
try
{
Running(this, new RunningEventArgs(Step, firstRun, StepRunTime));
var runningStartTime = DateTime.Now;
var runningTask = System.Threading.Tasks.Task.Run(() =>
{
try
{
runningHandler(this, new RunningEventArgs(Step, firstRun, StepRunTime));
}
catch (Exception ex)
{
RaiseMessage("SM-ERROR-RUNNING", $"Running Exception: {ex.Message}\n{ex.StackTrace}");
}
});
// 타임아웃 2초
if (!runningTask.Wait(2000))
{
var elapsed = (DateTime.Now - runningStartTime).TotalSeconds;
RaiseMessage("SM-TIMEOUT", $"Running 이벤트 타임아웃 ({elapsed:F2}초 초과) - Step:{Step}, FirstRun:{firstRun}");
}
}
catch (Exception ex)
{
RaiseMessage("SM-ERROR", ex.Message);
RaiseMessage("SM-ERROR-RUNNING", $"Running Exception: {ex.Message}\n{ex.StackTrace}");
}
} System.Threading.Thread.Sleep(1);
}
System.Threading.Thread.Sleep(1);
}
_isthreadrun = false;
if (GetMsgOpt(EMsgOpt.NORMAL)) RaiseMessage("SM", "Stop");
catch (Exception ex)
{
RaiseMessage("SM-FATAL", $"Loop Fatal Exception: {ex.Message}\n{ex.StackTrace}");
}
finally
{
_isthreadrun = false;
if (GetMsgOpt(EMsgOpt.NORMAL)) RaiseMessage("SM", $"Stop - LoopCount:{_loopCount}");
}
}
@@ -175,7 +246,18 @@ namespace Project.StateMachine
OldStep = _step;
_step = newstep_;
_newstep = newstep_;
StepChanged?.Invoke(this, new StepChangeEventArgs(OldStep, newstep_));
// 비동기로 이벤트 발생 (블로킹 방지)
var handler = StepChanged;
if (handler != null)
{
var args = new StepChangeEventArgs(OldStep, newstep_);
System.Threading.ThreadPool.QueueUserWorkItem(_ =>
{
try { handler(this, args); }
catch { /* 이벤트 핸들러 예외 무시 */ }
});
}
}
else
{
@@ -284,7 +366,18 @@ namespace Project.StateMachine
{
var ostep = _step;
OldStep = _step; _step = _newstep;
StepChanged?.Invoke(this, new StepChangeEventArgs(ostep, _step));
// 비동기로 이벤트 발생 (블로킹 방지)
var handler = StepChanged;
if (handler != null)
{
var args = new StepChangeEventArgs(ostep, _step);
System.Threading.ThreadPool.QueueUserWorkItem(_ =>
{
try { handler(this, args); }
catch { /* 이벤트 핸들러 예외 무시 */ }
});
}
} //171214
/// <summary>