由于框架限制需要保留同步方式(避免异步编程如 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"; }
        }
    }
}

优化要点说明

  1. 统一锁顺序:
    • 在 RateQuery、_HEATRise、_HEATOFF 和 _HEATON 中,锁获取顺序固定为:先 HardwareMgr.HeatBoardLockers[HeatBoardGroup],再 IoMgr.HdLockers[com]。
    • 使用 Monitor.TryEnter 替代 lock,设置 5 秒超时,防止死锁或无限阻塞。
    • 日志记录锁的获取和释放,方便调试死锁问题。
  2. 引入信号量:
    • 使用 Semaphore(同步版本的 SemaphoreSlim)限制硬件并发访问,每次只允许一个线程调用硬件接口。
    • 超时设置为 5 秒,失败时记录日志并抛出异常。
  3. 线程安全集合:
    • 将 ParameterMap 替换为 ConcurrentDictionary<string, object>,使用 TryGetValue 安全访问参数。
    • HeatBoardRealTimeState 使用内部锁保护 TempValue 和 WorkStatus,返回数组副本防止外部修改。
  4. 合并硬件操作:
    • _HEATRise 使用 HEATONESTEPSET 指令,替代单独的 _HEATOFF、HEATSET 和 _HEATON,减少硬件调用和锁获取次数。
    • 原 _HEATOFF 和 _HEATON 方法保留,用于其他场景。
  5. 减少重试次数:
    • QueryData 的重试次数从 5 次减少到 3 次,降低硬件阻塞时间。
    • 每次重试记录日志,显示错误码,便于调试。
  6. 增强日志:
    • 在锁获取、释放、硬件调用和关键操作点添加详细日志,包含线程 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 减少硬件调用,显著降低卡顿概率。
    • 详细日志帮助定位是否是锁竞争或硬件问题。

实施建议

  1. 验证锁顺序:
    • 检查 HeatBoardLockers 和 HdLockers 的分配,确保每个加热区和硬件接口的锁对象正确映射。
    • 运行测试,观察日志中的锁获取和释放顺序,确认无死锁。
  2. 测试硬件响应:
    • 单独测试 HeatBoardInterop.LabVIEWExports.OFF 和 SET,确保硬件调用不超过 5 秒。
    • 如果硬件响应慢,考虑调整超时时间或优化硬件接口。
  3. 逐步部署:
    • 先替换 ParameterMap 为 ConcurrentDictionary,验证参数访问的正确性。
    • 引入 Semaphore 和 HEATONESTEPSET,测试高并发场景(如 4 个加热区同时操作)。
    • 最后添加超时锁和详细日志,监控系统稳定性。
  4. 日志监控:
    • 部署后检查日志,关注锁超时、信号量超时和硬件错误。
    • 示例关注点:
      • Lock timeout for Com1:表示锁竞争严重,需检查 Com 分配。
      • Semaphore timeout:表示硬件访问冲突,需优化硬件调用。
  5. 性能测试:
    • 在多加热区并发场景下测试,确保程序不再卡顿,且温度设置和读取正常。

总结优化后的代码保留了同步编程方式,通过以下措施解决了卡在 _HEATOFF 的问题:

  • 统一锁顺序和超时机制,防止死锁和无限阻塞。
  • 使用 ConcurrentDictionary 确保 ParameterMap 线程安全。
  • 引入 Semaphore 限制硬件并发访问。
  • 合并硬件操作为 HEATONESTEPSET,减少锁和硬件调用。
  • 增强日志记录,方便定位问题。

这些改进显著降低了死锁和锁竞争风险,提高了程序的稳定性和并发性能。建议优先验证锁顺序和硬件响应时间,逐步实施优化,并通过日志监控确保系统正常运行。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐