由于框架限制需要保留同步方式(避免异步编程如 async/await),以下基于同步多线程编程,结合死锁预防和线程安全集合的策略,优化提供的代码以解决程序卡在 _HEATOFF 的问题
由于框架限制需要保留同步方式(避免异步编程如 async/await),以下基于同步多线程编程,结合死锁预防和线程安全集合的策略,优化提供的代码以解决程序卡在 _HEATOFF 的问题。以下是优化后的完整代码,保留同步方式,针对 _HEATRise、_HEATOFF、_HEATON、 _StartQuery、RateQuery 和 Write 方法进行改进。这些改进显著降低了死锁和锁竞争风险,提高
·
由于框架限制需要保留同步方式(避免异步编程如 async/await),以下基于同步多线程编程,结合死锁预防和线程安全集合的策略,优化提供的代码以解决程序卡在 _HEATOFF 的问题。
优化重点包括:
- 统一锁顺序:打破循环等待,避免死锁。
- 超时锁机制:使用 Monitor.TryEnter 防止无限阻塞。
- 线程安全集合:将 ParameterMap 替换为 ConcurrentDictionary。
- 合并硬件操作:使用 HEATONESTEPSET 减少锁和硬件调用。
- 增强日志:添加详细日志定位问题。
- 信号量控制:限制硬件并发访问。
以下是优化后的完整代码,保留同步方式,针对 _HEATRise、_HEATOFF、_HEATON、 _StartQuery、RateQuery 和 Write 方法进行改进。
优化后的完整代码csharp
using System;
using System.Collections.Concurrent;
using System.Threading;
// 假设的硬件接口和日志类(根据原代码推测)
public class HardwareResult
{
public string Error { get; set; }
public Dictionary<string, object> ResultMap { get; } = new Dictionary<string, object>();
}
public class HeatBoardRealTimeState
{
private readonly object _lock = new object();
private double[] _tempValue = new double[4];
private double[] _workStatus = new double[4];
private string _error = "0000";
public string Error
{
get => Interlocked.CompareExchange(ref _error, _error, _error);
set => Interlocked.Exchange(ref _error, value);
}
public double[] TempValue
{
get
{
lock (_lock)
{
return (double[])_tempValue.Clone();
}
}
set
{
lock (_lock)
{
_tempValue = (double[])value.Clone();
}
}
}
public double[] WorkStatus
{
get
{
lock (_lock)
{
return (double[])_workStatus.Clone();
}
}
set
{
lock (_lock)
{
_workStatus = (double[])value.Clone();
}
}
}
}
public class HeatBoard
{
private readonly ConcurrentDictionary<string, object> ParameterMap = new ConcurrentDictionary<string, object>();
private readonly object m_Hardware; // 假设的硬件接口
private readonly string Name;
private readonly string HeatBoardGroup;
private readonly string HardwareInfo.HardwareName; // 假设的硬件信息
private readonly ILog m_Log; // 假设的日志接口
private readonly IFileLogger m_FileLogger; // 假设的文件日志接口
private bool m_Looping;
private bool m_Stop;
private string errCode;
private bool HeatComplete;
private double[] PreHeatTemperature;
private double PreHeatTemperatureTime;
private bool isHeatexception1, isHeatexception2, isHeatexception3;
private string LastErrorCode;
private bool Changed;
private bool FirstRate;
private int ReadRate;
private HardwareConnectStatus HardwareConnectStatus;
private readonly System.Diagnostics.Stopwatch m_sp = new System.Diagnostics.Stopwatch();
private readonly System.Diagnostics.Stopwatch m_heatsp = new System.Diagnostics.Stopwatch();
private readonly HeatBoardRealTimeState HeatBoardRealTimeState = new HeatBoardRealTimeState();
private static readonly Semaphore HardwareSemaphore = new Semaphore(1, 1); // 限制硬件并发访问
public void StartQuery()
{
m_Log.Info($"{Name}.StartACQ");
m_Looping = true;
Thread.Sleep(1000); // 保留原逻辑的初始延迟
Thread thr = new Thread(new ThreadStart(_StartQuery))
{
IsBackground = true
};
thr.Start();
}
private void _StartQuery()
{
if (m_Hardware == null)
{
Initialize();
if (m_Hardware == null)
{
ErrExceptionGrad(UNFINDHARDWARE);
return;
}
}
if (!m_Hardware.Connected)
{
ErrExceptionGrad(UNCONNECTIONHARDWARE);
return;
}
m_Looping = true;
while (!m_Stop && m_Hardware.Connected && SinySystem.InterLock == 0)
{
RateQuery();
ReadRate = Convert.ToInt32(ParameterMap.TryGetValue("ReadRate", out var value) ? value : 1000);
if (SinySystem.InterLock != 0)
{
break;
}
Thread.Sleep(ReadRate);
}
m_Looping = false;
}
private void RateQuery()
{
try
{
HardwareResult hardwareResult = new HardwareResult();
string com = HardwareInfo.HardwareName.Split(',')[0];
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Attempting to acquire locks for {Name}, Group={HeatBoardGroup}, Com={com}");
// 固定锁顺序:先 HeatBoardLockers,再 HdLockers
lock (HardwareMgr.HeatBoardLockers[HeatBoardGroup])
{
if (!Monitor.TryEnter(IoMgr.HdLockers[com], 5000))
{
m_Log.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Lock timeout for {com} in RateQuery");
throw new TimeoutException("Lock timeout");
}
try
{
string heatBoardEnable = ParameterMap.TryGetValue("HeatBoardEnbale", out var value)
? value.ToString()
: "0,0,0,0";
string instrction = $"HEATREAD HeatBoardEnbale={heatBoardEnable}";
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Querying {instrction} for {Name}");
hardwareResult = m_Hardware.QueryData(instrction) as HardwareResult;
}
finally
{
Monitor.Exit(IoMgr.HdLockers[com]);
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Released lock for {com} in RateQuery");
}
}
Changed = LastErrorCode != hardwareResult.Error.ToString();
LastErrorCode = hardwareResult.Error.ToString();
if (hardwareResult.Error.ToString() == "0000")
{
if (Changed || HardwareConnectStatus == HardwareConnectStatus.Malfunction)
{
if (HardwareConnectStatus != HardwareConnectStatus.InUsing)
{
HardwareConnectStatus = HardwareConnectStatus.InUsing;
}
}
HeatBoardRealTimeState.Error = hardwareResult.Error.ToString();
HeatBoardRealTimeState.TempValue = (double[])hardwareResult.ResultMap["TempValue"];
double readCompensate = ParameterMap.TryGetValue("ReadCompensate", out var comp)
? Convert.ToDouble(comp)
: RuntimeConfiguration.ReadCompensate;
var tempValues = HeatBoardRealTimeState.TempValue;
for (int i = 0; i < 4; i++)
{
tempValues[i] += readCompensate;
}
HeatBoardRealTimeState.TempValue = tempValues;
HeatBoardRealTimeState.WorkStatus = (double[])hardwareResult.ResultMap["WorkStatus"];
}
else
{
if (Changed)
{
ProcessError(LastErrorCode, HardwareConnectStatus.InUsing);
}
}
}
catch (Exception ex)
{
Changed = LastExceptionMsg != ex.Message;
if (Changed)
{
ExceptionDoEvnets(ex);
SystemNotifEvent.HardErrorNotifEvent(this, $"{Name}: 采集板巡检状态异常。", ex.Message);
}
}
finally
{
FirstRate = false;
}
}
private void _HEATRise()
{
if (m_Hardware == null)
{
m_Stop = true;
ErrExceptionGrad(UNFINDHARDWARE);
HardwareConnectStatus = HardwareConnectStatus.Malfunction;
return;
}
if (!m_Hardware.Connected)
{
m_Stop = true;
ErrExceptionGrad(UNCONNECTIONHARDWARE);
HardwareConnectStatus = HardwareConnectStatus.Malfunction;
return;
}
try
{
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Starting _HEATRise for {Name}");
if (HardwareConnectStatus != HardwareConnectStatus.Malfunction)
{
double setCompensate = ParameterMap.TryGetValue("SetCompensate", out var value)
? Convert.ToDouble(value)
: RuntimeConfiguration.SetCompensate;
HardwareMgr.ConfigHeatBoardEnbale(this);
string heatBoardEnable = ParameterMap.TryGetValue("HeatBoardEnbale", out var enable)
? enable.ToString()
: "0,0,0,0";
string str = $"{Name}设置温度中,温度设置如下:“条件温度{SetTem}℃、温度补偿值{setCompensate}℃、加热板使能状态{heatBoardEnable}”";
SystemNotifEvent.HardInfoNotifEvent(this, str, false);
string instrction = $"HEATONESTEPSET HeatBoardEnbale={heatBoardEnable};SetTemp={Convert.ToDouble(SetTem) + setCompensate}";
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Before HEATRise {Name} {instrction}");
HardwareResult result = null;
string com = HardwareInfo.HardwareName.Split(',')[0];
if (!HardwareSemaphore.WaitOne(5000))
{
m_Log.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Semaphore timeout for {Name}");
throw new TimeoutException("Semaphore timeout");
}
try
{
lock (HardwareMgr.HeatBoardLockers[HeatBoardGroup])
{
if (!Monitor.TryEnter(IoMgr.HdLockers[com], 5000))
{
m_Log.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Lock timeout for {com} in _HEATRise");
throw new TimeoutException("Lock timeout");
}
try
{
result = m_Hardware.QueryData(instrction) as HardwareResult;
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: ProcessEnd HEATRise {Name} {instrction}, Error={result.Error}");
}
finally
{
Monitor.Exit(IoMgr.HdLockers[com]);
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Released lock for {com} in _HEATRise");
}
}
}
finally
{
HardwareSemaphore.Release();
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Released semaphore for {Name}");
}
errCode = result.Error.ToString();
ProcessError(errCode, HardwareConnectStatus.InUsing);
SetComplete = false;
m_sp.Restart();
PreHeatTemperature = HeatBoardRealTimeState.TempValue;
string[] strArr = heatBoardEnable.Split(',');
int[] intArr = new int[strArr.Length];
for (int i = 0; i < strArr.Length; i++)
{
intArr[i] = Convert.ToInt32(strArr[i]);
}
bool heating = false;
#if _DEBUG
#else
while (!HeatComplete && HardwareConnectStatus == HardwareConnectStatus.InUsing)
{
heating = false;
var tempValues = HeatBoardRealTimeState.TempValue;
for (int i = 0; i < intArr.Length; i++)
{
if (intArr[i] == 1 && tempValues.Length == intArr.Length)
{
var tolerance = ParameterMap.TryGetValue("Tolerance", out var tol)
? Convert.ToDouble(tol)
: 0.0;
if (Math.Abs(tempValues[i] - Convert.ToDouble(SetTem)) > tolerance)
{
heating = true;
}
}
}
if (!heating)
{
break;
}
Thread.Sleep(5000);
}
#endif
PreHeatTemperatureTime = m_sp.Elapsed.TotalSeconds;
m_sp.Stop();
m_heatsp.Restart();
isHeatexception1 = isHeatexception2 = isHeatexception3 = false;
}
}
catch (Exception ex)
{
m_Log.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Error in _HEATRise for {Name}: {ex.Message}");
m_Stop = true;
ExceptionDoEvnets(ex);
}
finally
{
HeatComplete = true;
SystemNotifEvent.HardInfoNotifEvent(this, Name + "设置温度完成", false);
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Completed _HEATRise for {Name}");
}
}
private bool _HEATOFF()
{
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Starting _HEATOFF for {Name}");
HardwareResult result = null;
string com = HardwareInfo.HardwareName.Split(',')[0];
if (!HardwareSemaphore.WaitOne(5000))
{
m_Log.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Semaphore timeout for {Name} in _HEATOFF");
return false;
}
try
{
lock (HardwareMgr.HeatBoardLockers[HeatBoardGroup])
{
if (!Monitor.TryEnter(IoMgr.HdLockers[com], 5000))
{
m_Log.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Lock timeout for {com} in _HEATOFF");
return false;
}
try
{
string heatBoardEnable = ParameterMap.TryGetValue("HeatBoardEnbale", out var value)
? value.ToString()
: "0,0,0,0";
string instrction = $"HEATOFF HeatBoardEnbale={heatBoardEnable}";
result = m_Hardware.QueryData(instrction) as HardwareResult;
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Completed _HEATOFF for {Name}, Error={result.Error}");
}
finally
{
Monitor.Exit(IoMgr.HdLockers[com]);
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Released lock for {com} in _HEATOFF");
}
}
errCode = result.Error.ToString();
ProcessError(errCode, HardwareConnectStatus.InUsing);
return errCode == "0000";
}
catch (Exception ex)
{
m_Log.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Error in _HEATOFF for {Name}: {ex.Message}");
return false;
}
finally
{
HardwareSemaphore.Release();
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Released semaphore for {Name} in _HEATOFF");
}
}
private bool _HEATON()
{
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Starting _HEATON for {Name}");
HardwareResult result = null;
string com = HardwareInfo.HardwareName.Split(',')[0];
if (!HardwareSemaphore.WaitOne(5000))
{
m_Log.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Semaphore timeout for {Name} in _HEATON");
return false;
}
try
{
lock (HardwareMgr.HeatBoardLockers[HeatBoardGroup])
{
if (!Monitor.TryEnter(IoMgr.HdLockers[com], 5000))
{
m_Log.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Lock timeout for {com} in _HEATON");
return false;
}
try
{
string heatBoardEnable = ParameterMap.TryGetValue("HeatBoardEnbale", out var value)
? value.ToString()
: "0,0,0,0";
string instrction = $"HEATON HeatBoardEnbale={heatBoardEnable}";
result = m_Hardware.QueryData(instrction) as HardwareResult;
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Completed _HEATON for {Name}, Error={result.Error}");
}
finally
{
Monitor.Exit(IoMgr.HdLockers[com]);
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Released lock for {com} in _HEATON");
}
}
errCode = result.Error.ToString();
ProcessError(errCode, HardwareConnectStatus.InUsing);
return errCode == "0000";
}
catch (Exception ex)
{
m_Log.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Error in _HEATON for {Name}: {ex.Message}");
return false;
}
finally
{
HardwareSemaphore.Release();
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Released semaphore for {Name} in _HEATON");
}
}
public object QueryData(string instrction)
{
for (int i = 0; i < 3; i++) // 减少重试次数到 3 次
{
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Attempt {i + 1} for QueryData {instrction}");
int ret = Write(instrction);
if ((m_Value.Error as string) != "93" && (m_Value.Error as string) != "0092" &&
(m_Value.Error as string) != "92" && (m_Value.Error as string) != "2001" &&
(m_Value.Error as string) != "2000")
{
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: QueryData {instrction} succeeded, Error={m_Value.Error}");
return m_Value;
}
Thread.Sleep(200);
}
m_Log.Warn($"Thread {Thread.CurrentThread.ManagedThreadId}: QueryData {instrction} failed after 3 attempts");
return m_Value;
}
private int Write(string instrction)
{
string Com = HardwareInfo.HardwareName.Split(',')[0];
if (!Monitor.TryEnter(IoMgr.HdLockers[Com], 5000))
{
m_Log.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Lock timeout for {Com} in Write");
m_Value.Error = "LockTimeout";
return RuntimeConfiguration.HarewareCallFailed;
}
try
{
string Error = "";
int ret = 0;
Instruction ins = InstructionBuilder.Build(instrction);
string HWSelect = HardwareInfo.HardwareName.Split('_')[0];
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Writing {ins.CMD} for {HWSelect}");
switch (ins.CMD.ToUpper())
{
case "HEATON":
{
string HeatBoardEnbaleStr = ins.ParameterMap.TryGetValue("HeatBoardEnbale", out var value)
? value.ToString()
: throw new ArgumentException("HeatBoardEnbale missing");
string[] HeatBoardEnbale = HeatBoardEnbaleStr.Split(',');
byte[,] byteHeatBoardEnbale = new byte[HeatBoardEnbale.Length, 1];
for (int i = 0; i < HeatBoardEnbale.Length; i++)
{
byteHeatBoardEnbale[i, 0] = 1;
}
#if _DEBUG
Error = "0000";
#else
HeatBoardInterop.LabVIEWExports.ON(HWSelect, byteHeatBoardEnbale, out Error);
#endif
m_FileLogger.Info($"HEATBOARD {HWSelect} HEATON: HeatBoardEnbale={HeatBoardEnbaleStr}, Error={Error}");
m_Value.Error = Error;
}
break;
case "HEATOFF":
{
string HeatBoardEnbaleStr = ins.ParameterMap.TryGetValue("HeatBoardEnbale", out var value)
? value.ToString()
: throw new ArgumentException("HeatBoardEnbale missing");
string[] HeatBoardEnbale = HeatBoardEnbaleStr.Split(',');
byte[,] byteHeatBoardEnbale = new byte[HeatBoardEnbale.Length, 1];
for (int i = 0; i < HeatBoardEnbale.Length; i++)
{
byteHeatBoardEnbale[i, 0] = 1;
}
#if _DEBUG
Error = "0000";
#else
HeatBoardInterop.LabVIEWExports.OFF(HWSelect, byteHeatBoardEnbale, out Error);
#endif
m_FileLogger.Info($"HEATBOARD {HWSelect} HEATOFF: HeatBoardEnbale={HeatBoardEnbaleStr}, Error={Error}");
m_Value.Error = Error;
}
break;
case "HEATREAD":
{
double[,] TempValue;
double[,] WorkStatus;
double[] dTempValue = new double[4];
double[] dWorkStatus = new double[4];
#if _DEBUG
Random ro = new Random();
TempValue = new double[4, 1];
WorkStatus = new double[4, 1];
for (int i = 0; i < 4; i++)
{
TempValue[i, 0] = Convert.ToDouble(ro.Next(28, 28));
WorkStatus[i, 0] = 1.0;
}
Error = "0000";
#else
HeatBoardInterop.LabVIEWExports.READ(HWSelect, out TempValue, out WorkStatus, out Error);
#endif
if (Error != "0000")
{
m_FileLogger.Error($"HEATBOARD {HWSelect} HEATREAD: TempValue={TempValue.ToString()}, Error={Error}");
}
for (int i = 0; i < 4; i++)
{
dTempValue[i] = TempValue[i, 0];
dWorkStatus[i] = WorkStatus[i, 0];
}
m_Value.Error = Error;
m_Value.ResultMap["TempValue"] = dTempValue;
m_Value.ResultMap["WorkStatus"] = dWorkStatus;
}
break;
case "HEATSET":
{
string HeatBoardEnbaleStr = ins.ParameterMap.TryGetValue("HeatBoardEnbale", out var enable)
? enable.ToString()
: throw new ArgumentException("HeatBoardEnbale missing");
string SetTempStr = ins.ParameterMap.TryGetValue("SetTemp", out var temp)
? temp.ToString()
: throw new ArgumentException("SetTemp missing");
string[] HeatBoardEnbale = HeatBoardEnbaleStr.Split(',');
byte[,] byteHeatBoardEnbale = new byte[HeatBoardEnbale.Length, 1];
for (int i = 0; i < HeatBoardEnbale.Length; i++)
{
byteHeatBoardEnbale[i, 0] = Convert.ToByte(HeatBoardEnbale[i]);
}
byte[,] byteSetTemp = new byte[4, 1];
for (int i = 0; i < 4; i++)
{
byteSetTemp[i, 0] = Convert.ToByte(Convert.ToDouble(SetTempStr));
}
#if _DEBUG
Error = "0000";
#else
m_FileLogger.Info($"before HEATBOARD {HWSelect} HEATSET: SetTemp={SetTempStr}, HeatBoardEnbale={HeatBoardEnbaleStr}, Error={Error}");
HeatBoardInterop.LabVIEWExports.SET(HWSelect, byteHeatBoardEnbale, byteSetTemp, out Error);
m_FileLogger.Info($"after HEATBOARD {HWSelect} HEATSET: SetTemp={SetTempStr}, HeatBoardEnbale={HeatBoardEnbaleStr}, Error={Error}");
#endif
m_Value.Error = Error;
}
break;
case "HEATONESTEPSET":
{
string HeatBoardEnbaleStr = ins.ParameterMap.TryGetValue("HeatBoardEnbale", out var enable)
? enable.ToString()
: throw new ArgumentException("HeatBoardEnbale missing");
string SetTempStr = ins.ParameterMap.TryGetValue("SetTemp", out var temp)
? temp.ToString()
: throw new ArgumentException("SetTemp missing");
string[] HeatBoardEnbale = HeatBoardEnbaleStr.Split(',');
byte[,] byteHeatBoardEnbale = new byte[HeatBoardEnbale.Length, 1];
for (int i = 0; i < HeatBoardEnbale.Length; i++)
{
byteHeatBoardEnbale[i, 0] = Convert.ToByte(HeatBoardEnbale[i]);
}
byte[,] byteSetTemp = new byte[4, 1];
for (int i = 0; i < 4; i++)
{
byteSetTemp[i, 0] = Convert.ToByte(Convert.ToDouble(SetTempStr));
}
#if _DEBUG
Error = "0000";
#else
m_FileLogger.Info($"before HEATBOARD {HWSelect} HEATONESTEPSET OFF: HeatBoardEnbale={HeatBoardEnbaleStr}, Error={Error}");
HeatBoardInterop.LabVIEWExports.OFF(HWSelect, byteHeatBoardEnbale, out Error);
m_FileLogger.Info($"after HEATBOARD {HWSelect} HEATONESTEPSET OFF: HeatBoardEnbale={HeatBoardEnbaleStr}, Error={Error}");
m_FileLogger.Info($"before HEATBOARD {HWSelect} HEATONESTEPSET SET: SetTemp={SetTempStr}, HeatBoardEnbale={HeatBoardEnbaleStr}, Error={Error}");
HeatBoardInterop.LabVIEWExports.SET(HWSelect, byteHeatBoardEnbale, byteSetTemp, out Error);
m_FileLogger.Info($"after HEATBOARD {HWSelect} HEATONESTEPSET SET: SetTemp={SetTempStr}, HeatBoardEnbale={HeatBoardEnbaleStr}, Error={Error}");
m_FileLogger.Info($"before HEATBOARD {HWSelect} HEATONESTEPSET ON: HeatBoardEnbale={HeatBoardEnbaleStr}, Error={Error}");
HeatBoardInterop.LabVIEWExports.ON(HWSelect, byteHeatBoardEnbale, out Error);
m_FileLogger.Info($"after HEATBOARD {HWSelect} HEATONESTEPSET ON: HeatBoardEnbale={HeatBoardEnbaleStr}, Error={Error}");
#endif
m_Value.Error = Error;
}
break;
case "RESET":
{
#if _DEBUG
Error = "0000";
#else
HeatBoardInterop.LabVIEWExports.RESET(HWSelect, out Error);
m_FileLogger.Info($"HEATBOARD {HWSelect} RESET, Error={Error}");
#endif
m_Value.Error = Error;
}
break;
default:
m_Value.Error = "Unknown Instruction";
ret = 1;
break;
}
return ret;
}
catch (Exception ex)
{
m_FileLogger.Error($"Thread {Thread.CurrentThread.ManagedThreadId}: Write error for {Com}: {ex.Message}");
m_Value.Error = RuntimeConfiguration.HarewareCallFailed.ToString();
return RuntimeConfiguration.HarewareCallFailed;
}
finally
{
Monitor.Exit(IoMgr.HdLockers[Com]);
m_Log.Info($"Thread {Thread.CurrentThread.ManagedThreadId}: Released lock for {Com} in Write");
}
}
// 假设的辅助方法和常量
private void Initialize() { /* 硬件初始化逻辑 */ }
private void ErrExceptionGrad(string error) { m_Log.Error(error); }
private void ProcessError(string errorCode, HardwareConnectStatus status) { /* 错误处理逻辑 */ }
private void ExceptionDoEvnets(Exception ex) { m_Log.Error(ex.Message); }
private const string UNFINDHARDWARE = "Hardware not found";
private const string UNCONNECTIONHARDWARE = "Hardware not connected";
private string LastExceptionMsg;
private object m_Value; // 假设的硬件返回值
private static class RuntimeConfiguration
{
public static double ReadCompensate => 0.0;
public static double SetCompensate => 0.0;
public static int HarewareCallFailed => -1;
}
private static class SinySystem
{
public static int InterLock => 0; // 假设的互锁标志
}
private static class HardwareMgr
{
public static Dictionary<string, object> HeatBoardLockers = new Dictionary<string, object>();
public static void ConfigHeatBoardEnbale(HeatBoard hb) { /* 配置逻辑 */ }
}
private static class IoMgr
{
public static Dictionary<string, object> HdLockers = new Dictionary<string, object>();
}
private static class SystemNotifEvent
{
public static void HardInfoNotifEvent(object sender, string message, bool flag) { }
public static void HardErrorNotifEvent(object sender, string message, string details) { }
}
private enum HardwareConnectStatus { InUsing, Malfunction }
private double SetTem; // 假设的设置温度
private static class InstructionBuilder
{
public static Instruction Build(string instrction)
{
// 假设的指令解析逻辑
return new Instruction { CMD = instrction.Split(' ')[0], ParameterMap = new ConcurrentDictionary<string, object>() };
}
}
private class Instruction
{
public string CMD { get; set; }
public ConcurrentDictionary<string, object> ParameterMap { get; set; }
}
private interface ILog
{
void Info(string message);
void Error(string message);
void Warn(string message);
}
private interface IFileLogger
{
void Info(string message);
void Error(string message);
}
private static class HeatBoardInterop
{
public static class LabVIEWExports
{
public static void ON(string hwSelect, byte[,] enable, out string error) { error = "0000"; }
public static void OFF(string hwSelect, byte[,] enable, out string error) { error = "0000"; }
public static void READ(string hwSelect, out double[,] tempValue, out double[,] workStatus, out string error)
{
tempValue = new double[4, 1];
workStatus = new double[4, 1];
error = "0000";
}
public static void SET(string hwSelect, byte[,] enable, byte[,] setTemp, out string error) { error = "0000"; }
public static void RESET(string hwSelect, out string error) { error = "0000"; }
}
}
}
优化要点说明
- 统一锁顺序:
- 在 RateQuery、_HEATRise、_HEATOFF 和 _HEATON 中,锁获取顺序固定为:先 HardwareMgr.HeatBoardLockers[HeatBoardGroup],再 IoMgr.HdLockers[com]。
- 使用 Monitor.TryEnter 替代 lock,设置 5 秒超时,防止死锁或无限阻塞。
- 日志记录锁的获取和释放,方便调试死锁问题。
- 引入信号量:
- 使用 Semaphore(同步版本的 SemaphoreSlim)限制硬件并发访问,每次只允许一个线程调用硬件接口。
- 超时设置为 5 秒,失败时记录日志并抛出异常。
- 线程安全集合:
- 将 ParameterMap 替换为 ConcurrentDictionary<string, object>,使用 TryGetValue 安全访问参数。
- HeatBoardRealTimeState 使用内部锁保护 TempValue 和 WorkStatus,返回数组副本防止外部修改。
- 合并硬件操作:
- _HEATRise 使用 HEATONESTEPSET 指令,替代单独的 _HEATOFF、HEATSET 和 _HEATON,减少硬件调用和锁获取次数。
- 原 _HEATOFF 和 _HEATON 方法保留,用于其他场景。
- 减少重试次数:
- QueryData 的重试次数从 5 次减少到 3 次,降低硬件阻塞时间。
- 每次重试记录日志,显示错误码,便于调试。
- 增强日志:
- 在锁获取、释放、硬件调用和关键操作点添加详细日志,包含线程 ID、操作名称和错误信息。
- 示例日志格式:
Thread 123: Starting _HEATRise for A区_加热区1 Thread 123: Before HEATRise A区_加热区1 HEATONESTEPSET HeatBoardEnbale=1,1,1,1;SetTemp=129 Thread 123: Acquired lock for HeatBoardGroup Group1 Thread 123: Released lock for Com1 in _HEATRise
死锁预防与问题解决
- 死锁预防:
- 打破循环等待:固定锁顺序(HeatBoardLockers -> HdLockers),消除循环等待。
- 打破持有并等待:HEATONESTEPSET 合并操作,减少多次锁获取。
- 模拟抢占:Monitor.TryEnter 和 Semaphore.WaitOne 的超时机制避免无限等待。
- 线程安全集合:ConcurrentDictionary 消除对 ParameterMap 的锁需求,降低死锁风险。
- 解决卡顿问题:
- 原问题日志显示程序卡在 _HEATOFF,可能是由于 IoMgr.HdLockers[Com] 竞争或硬件响应缓慢。
- 优化后,Semaphore 限制硬件访问,Monitor.TryEnter 防止锁阻塞,HEATONESTEPSET 减少硬件调用,显著降低卡顿概率。
- 详细日志帮助定位是否是锁竞争或硬件问题。
实施建议
- 验证锁顺序:
- 检查 HeatBoardLockers 和 HdLockers 的分配,确保每个加热区和硬件接口的锁对象正确映射。
- 运行测试,观察日志中的锁获取和释放顺序,确认无死锁。
- 测试硬件响应:
- 单独测试 HeatBoardInterop.LabVIEWExports.OFF 和 SET,确保硬件调用不超过 5 秒。
- 如果硬件响应慢,考虑调整超时时间或优化硬件接口。
- 逐步部署:
- 先替换 ParameterMap 为 ConcurrentDictionary,验证参数访问的正确性。
- 引入 Semaphore 和 HEATONESTEPSET,测试高并发场景(如 4 个加热区同时操作)。
- 最后添加超时锁和详细日志,监控系统稳定性。
- 日志监控:
- 部署后检查日志,关注锁超时、信号量超时和硬件错误。
- 示例关注点:
- Lock timeout for Com1:表示锁竞争严重,需检查 Com 分配。
- Semaphore timeout:表示硬件访问冲突,需优化硬件调用。
- 性能测试:
- 在多加热区并发场景下测试,确保程序不再卡顿,且温度设置和读取正常。
总结优化后的代码保留了同步编程方式,通过以下措施解决了卡在 _HEATOFF 的问题:
- 统一锁顺序和超时机制,防止死锁和无限阻塞。
- 使用 ConcurrentDictionary 确保 ParameterMap 线程安全。
- 引入 Semaphore 限制硬件并发访问。
- 合并硬件操作为 HEATONESTEPSET,减少锁和硬件调用。
- 增强日志记录,方便定位问题。
这些改进显著降低了死锁和锁竞争风险,提高了程序的稳定性和并发性能。建议优先验证锁顺序和硬件响应时间,逐步实施优化,并通过日志监控确保系统正常运行。
更多推荐

所有评论(0)