canbug修复

This commit is contained in:
hsc
2026-07-17 08:59:02 +08:00
parent 2dfc819bcc
commit 74d544c288
3 changed files with 83 additions and 23 deletions

View File

@@ -117,13 +117,23 @@ namespace MonitorModule.ViewModels.Dialogs
EnsureValueLimit(fingerprint, displayName, displayName, methodName);
}
// 3. 发现 CAN 信号并加入 ValueLimitList / DeviceSingleList
// 3. 发现 CAN 信号并加入 ValueLimitList,同时收集有效信号名
var validCanSignalNames = new HashSet<string>();
foreach (var (displayName, fingerprint, methodName) in DiscoverCanSignals())
{
//DeviceSingleList.Add(displayName);
_canSignalMap[displayName] = (fingerprint, methodName);
EnsureValueLimit(fingerprint, displayName, displayName, methodName);
validCanSignalNames.Add(displayName);
}
// 4. 清理已不存在于 DBC 中的 CAN 信号Fingerprint 以 "CAN" 开头且不在有效集合中)
var staleCanSignals = ValueLimitList
.Where(x => !string.IsNullOrEmpty(x.Fingerprint) &&
x.Fingerprint.StartsWith("CAN") &&
!validCanSignalNames.Contains(x.SignalName))
.ToList();
foreach (var item in staleCanSignals)
ValueLimitList.Remove(item);
}
/// <summary>

View File

@@ -83,7 +83,7 @@ namespace UIShare.UIViewModel
if (_series != null)
{
_series.Points.Add(new DataPoint(time, displayValue));
while (_series.Points.Count > 200)
while (_series.Points.Count > 10000)
{
_series.Points.RemoveAt(0);
}

View File

@@ -25,10 +25,11 @@ namespace ZLGUSBCANFD
// 异步高性能接收线程控制
private volatile bool _isRunning = false;
private volatile bool _isClosing = false; // 关闭流程标志:通知循环发送任务尽快退出
private readonly List<Thread> _receiveThreads = new List<Thread>();
// DBC 循环发送任务管理Key = (通道号, 帧ID)
private readonly ConcurrentDictionary<(uint , uint ID), CancellationTokenSource> _cyclicSenders = new ConcurrentDictionary<(uint, uint), CancellationTokenSource>();
// DBC 循环发送任务管理Key = (通道号, 帧ID)Value = (CTS, Task)
private readonly ConcurrentDictionary<(uint , uint ID), (CancellationTokenSource Cts, Task SendTask)> _cyclicSenders = new ConcurrentDictionary<(uint, uint), (CancellationTokenSource, Task)>();
// 信号值持久化覆盖表Key = (通道号, 帧ID)Value = 信号名 → 物理值
// 每次 设置报文 会累积写入此表,发送时以 DBC 初始值为底再叠加此表覆盖值
@@ -98,15 +99,17 @@ namespace ZLGUSBCANFD
/// </summary>
public virtual bool (uint )
{
_isClosing = false; // 重置关闭标志,允许循环发送
if (_deviceHandle == IntPtr.Zero) throw new InvalidOperationException("请先调用 '打开设备()' 才能初始化通道。");
if ( >= _maxChannels) return false;
lock (_channelLocks[])
{
// 如果已经启动过,先复位
// 如果已经启动过,直接退出
if (_channelHandles[] != IntPtr.Zero)
{
ZLGCAN.ZCAN_ResetCAN(_channelHandles[]);
return true;
//ZLGCAN.ZCAN_ResetCAN(_channelHandles[通道号]);
}
// 1. 设置该通道专属的仲裁域与数据域波特率
@@ -150,19 +153,44 @@ namespace ZLGUSBCANFD
public virtual void CAN卡设备()
{
_isRunning = false;
();
Thread.Sleep(50); // 确保轮询线程安全退出
_isClosing = true; // 通知循环发送任务尽快退出
_isRunning = false; // 通知接收轮询线程退出
(); // 内部会等待所有循环发送 Task 退出
// 等待所有接收轮询线程真正退出(每个最多 1 秒)
foreach (var thread in _receiveThreads)
{
if (thread.IsAlive)
thread.Join(1000);
}
_receiveThreads.Clear();
//动态复位所有通道并释放DBC
// 动态复位所有通道并释放 DBC(使用 TryEnter 防止死锁)
for (uint i = 0; i < _maxChannels; i++)
{
lock (_channelLocks[i])
if (Monitor.TryEnter(_channelLocks[i], TimeSpan.FromSeconds(2)))
{
try
{
if (_channelHandles[i] != IntPtr.Zero)
{
ZLGCAN.ZCAN_ResetCAN(_channelHandles[i]);
_channelHandles[i] = IntPtr.Zero;
}
DBC(i);
}
finally
{
Monitor.Exit(_channelLocks[i]);
}
}
else
{
// 锁超时:循环发送 Task 可能仍阻塞在原生 API 调用中,强制清理
LoggerHelper.Info($"[ZLGCANFD] 关闭通道 {i} 时获取锁超时,强制清理");
if (_channelHandles[i] != IntPtr.Zero)
{
ZLGCAN.ZCAN_ResetCAN(_channelHandles[i]);
try { ZLGCAN.ZCAN_ResetCAN(_channelHandles[i]); } catch { }
_channelHandles[i] = IntPtr.Zero;
}
DBC(i);
@@ -175,6 +203,8 @@ namespace ZLGUSBCANFD
ZLGCAN.ZCAN_CloseDevice(_deviceHandle);
_deviceHandle = IntPtr.Zero;
}
_isClosing = false;
}
#endregion
@@ -354,17 +384,16 @@ namespace ZLGUSBCANFD
(, ID);
var cts = new CancellationTokenSource();
_cyclicSenders[(, ID)] = cts;
Task.Run(async () =>
var sendTask = Task.Run(async () =>
{
while (!cts.Token.IsCancellationRequested)
{
if (_isClosing) break; // 关闭流程中立即退出
try
{
lock (_channelLocks[])
{
if (_channelHandles[] == IntPtr.Zero) break;
if (_channelHandles[] == IntPtr.Zero || _isClosing) break;
DBC定义报文单次(, ID, , 使CANFD);
}
@@ -382,13 +411,15 @@ namespace ZLGUSBCANFD
}
// 清理:仅当字典中存的仍然是本任务创建的 CTS 时才移除,避免误删新任务的 CTS
if (_cyclicSenders.TryGetValue((, ID), out var current) && ReferenceEquals(current, cts))
if (_cyclicSenders.TryGetValue((, ID), out var current) && ReferenceEquals(current.Cts, cts))
{
_cyclicSenders.TryRemove((, ID), out _);
}
cts.Dispose();
}, cts.Token);
_cyclicSenders[(, ID)] = (cts, sendTask);
return true;
}
@@ -397,9 +428,9 @@ namespace ZLGUSBCANFD
/// </summary>
public virtual void (uint , uint ID)
{
if (_cyclicSenders.TryRemove((, ID), out var cts))
if (_cyclicSenders.TryRemove((, ID), out var entry))
{
cts.Cancel();
entry.Cts.Cancel();
// 不在这里 Dispose由 Task 的清理代码负责释放,避免 Task 仍在使用已释放的 Token
}
}
@@ -409,11 +440,30 @@ namespace ZLGUSBCANFD
/// </summary>
public virtual void ()
{
foreach (var kvp in _cyclicSenders)
var entries = _cyclicSenders.ToArray();
// 1. 取消所有 CTS不 Dispose由 Task 清理代码负责)
foreach (var kvp in entries)
{
kvp.Value.Cancel();
kvp.Value.Dispose();
kvp.Value.Cts.Cancel();
}
// 2. 等待所有循环发送 Task 退出(最多 3 秒)
var tasks = new List<Task>();
foreach (var kvp in entries)
{
if (!kvp.Value.SendTask.IsCompleted)
tasks.Add(kvp.Value.SendTask);
}
if (tasks.Count > 0)
{
try
{
Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(3));
}
catch { /* 忽略等待异常 */ }
}
_cyclicSenders.Clear();
}