.NET 程式除錯較 C/C++ 容易,但仍難以應對:
本文實作一個 ThreadMonitor 類別,以獨立高優先權監控線程,即時偵測並報告上述異常。
public class ThreadMonitor
{
private Thread _monitorThread;
private Dictionary<int, TCB> _tcbTable = new Dictionary<int, TCB>();
private object _registerLock = new object();
public ThreadMonitor()
{
_monitorThread = new Thread(MonitorTask) { Priority = ThreadPriority.Highest, IsBackground = true };
}
public void Start() => _monitorThread.Start();
public void Register(MonitorParameter mp)
{
lock (_registerLock)
_tcbTable[mp.Thread.ManagedThreadId] = new TCB(mp);
}
public void Heartbeat(Thread t)
{
var tcb = GetTCB(t);
tcb.LastHeartbeat = DateTime.Now;
tcb.HitTimes = 0;
tcb.Status &= ~ThreadStatus.Hang;
}
// ... 監控邏輯詳見下文
}
Heartbeat()(如每秒一次)。LastHeartbeat,超過 HangTimeout 視為掛起。Thread.Suspend() 暫停目標線程,取得 StackTrace,再 Resume() 恢復。private string GetThreadStackTrace(Thread t)
{
t.Suspend();
var stack = new StackTrace(t, true);
t.Resume();
return stack.ToString();
}
注意: Suspend/Resume 已被標記過時,但此處僅用於瞬間取得堆疊,風險可控。
Process.TotalProcessorTime 計算進程 CPU 使用率。90% * (100 / 核心數),判定進程疑似死循環。Running 且無心跳,鎖定為死循環源頭。ThreadMonitorEvent
Thread Name: Main thread
Thread Status: Hang
Thread Stack:
at System.Threading.Thread.SleepInternal(Int32 millisecondsTimeout)
at DotNetDebug.Form1.buttonHang_Click(Object sender, EventArgs e)
...
ThreadMonitorEvent
Thread Name: Counter thread
Thread Status: Hang, DeadCycle
Thread Stack:
at DotNetDebug.Form1.DoDeadCycle()
at DotNetDebug.Form1.Counter()
...
Timer 每秒送心跳給主線程Thread.Sleep(20000) 或 _DeadCycle = trueReport.log