设备销毁处理

This commit is contained in:
hsc
2026-06-24 10:08:38 +08:00
parent cd3cbe7c35
commit c4470af013
2 changed files with 64 additions and 1 deletions

View File

@@ -15,11 +15,12 @@ namespace UIShare.GlobalVariable
/// 设备管理器:根据 <see cref="SystemConfig.DeviceList"/> 反射实例化所有启用的设备, /// 设备管理器:根据 <see cref="SystemConfig.DeviceList"/> 反射实例化所有启用的设备,
/// 通过 <see cref="IBaseInterface"/> 多态统一管理,避免为每种设备单独硬编码字段。 /// 通过 <see cref="IBaseInterface"/> 多态统一管理,避免为每种设备单独硬编码字段。
/// </summary> /// </summary>
public class DeviceManager public class DeviceManager:IDisposable
{ {
private object _lockObj = new object(); private object _lockObj = new object();
public SystemConfig _systemConfig { get; set; } public SystemConfig _systemConfig { get; set; }
private readonly GlobalInfo _globalInfo; private readonly GlobalInfo _globalInfo;
private readonly string _scopeName;
/// <summary>按 DeviceName 索引的设备字典,便于业务层按名取实例。</summary> /// <summary>按 DeviceName 索引的设备字典,便于业务层按名取实例。</summary>
public IDictionary<string, IBaseInterface> DeviceMap { get; private set; } public IDictionary<string, IBaseInterface> DeviceMap { get; private set; }
@@ -32,6 +33,8 @@ namespace UIShare.GlobalVariable
{ {
_systemConfig = systemConfig; _systemConfig = systemConfig;
_globalInfo = globalInfo; _globalInfo = globalInfo;
// 用 SystemConfig.Title 作为作用域唯一标识,无需反查 ConfigDic
_scopeName = _systemConfig.Title;
InitDevices(); InitDevices();
} }
/// <summary> /// <summary>
@@ -108,6 +111,18 @@ namespace UIShare.GlobalVariable
DeviceMap[config.DeviceName] = instance; DeviceMap[config.DeviceName] = instance;
} }
// 第五步:将当前作用域注册到指纹的作用域列表,用于引用计数与安全销毁
if (!string.IsNullOrEmpty(_scopeName))
{
var scopeList = _globalInfo.DeviceAndScopeDic.GetOrAdd(fingerprint,
_ => new Lazy<List<string>>(() => new List<string>())).Value;
lock (scopeList)
{
if (!scopeList.Contains(_scopeName))
scopeList.Add(_scopeName);
}
}
LoggerHelper.Info($"已加载设备 [{config.DeviceName} / {config.DeviceType} / {config.ConnectionType}] 指纹={fingerprint}"); LoggerHelper.Info($"已加载设备 [{config.DeviceName} / {config.DeviceType} / {config.ConnectionType}] 指纹={fingerprint}");
} }
catch (Exception ex) catch (Exception ex)
@@ -338,6 +353,50 @@ namespace UIShare.GlobalVariable
}; };
return Activator.CreateInstance(type, cfg) as IBaseInterface; return Activator.CreateInstance(type, cfg) as IBaseInterface;
} }
public void Dispose()
{
if (string.IsNullOrEmpty(_scopeName)) return;
// 遍历当前作用域用到的所有指纹,逐一移除本作用域的引用
var fingerprintsToRemove = new List<string>();
foreach (var kvp in _globalInfo.DeviceAndScopeDic)
{
string fingerprint = kvp.Key;
var scopeList = kvp.Value.IsValueCreated ? kvp.Value.Value : null;
if (scopeList == null) continue;
lock (scopeList)
{
scopeList.Remove(_scopeName);
// 引用归零 → 标记为待清理
if (scopeList.Count == 0)
fingerprintsToRemove.Add(fingerprint);
}
}
// 对引用归零的指纹:销毁设备实例 + 从全局池中移除
foreach (var fingerprint in fingerprintsToRemove)
{
// 尝试从 HardwarePool 取出并销毁
if (_globalInfo.HardwarePool.TryRemove(fingerprint, out var lazy))
{
if (lazy.IsValueCreated && lazy.Value is IBaseInterface device)
{
try { device.Close(); }
catch { /* 销毁时忽略异常 */ }
LoggerHelper.Info($"指纹 [{fingerprint}] 无作用域引用,已销毁设备实例。");
}
}
// 同步清除 DeviceAndScopeDic 中的空条目
_globalInfo.DeviceAndScopeDic.TryRemove(fingerprint, out _);
}
DeviceMap.Clear();
}
#endregion #endregion
} }
} }

View File

@@ -19,6 +19,9 @@ namespace UIShare.GlobalVariable
/// <summary>硬件指纹 → 设备实例的并发池,确保同一物理硬件全局只创建一个驱动实例。</summary> /// <summary>硬件指纹 → 设备实例的并发池,确保同一物理硬件全局只创建一个驱动实例。</summary>
public ConcurrentDictionary<string, Lazy<IBaseInterface>> HardwarePool { get; set; } public ConcurrentDictionary<string, Lazy<IBaseInterface>> HardwarePool { get; set; }
/// <summary>硬件指纹 → 正在使用该设备的作用域名称列表,用于引用计数与安全销毁。</summary>
public ConcurrentDictionary<string, Lazy<List<string>>> DeviceAndScopeDic { get; set; }
public String UserName { get; set; } = "Not Logged in"; public String UserName { get; set; } = "Not Logged in";
public bool IsAdmin { get; set; } = true; public bool IsAdmin { get; set; } = true;
public string CurrentOpeningScope; public string CurrentOpeningScope;
@@ -42,6 +45,7 @@ namespace UIShare.GlobalVariable
ConfigDic = new(); ConfigDic = new();
ScopeDic = new(); ScopeDic = new();
HardwarePool = new ConcurrentDictionary<string, Lazy<IBaseInterface>>(StringComparer.OrdinalIgnoreCase); HardwarePool = new ConcurrentDictionary<string, Lazy<IBaseInterface>>(StringComparer.OrdinalIgnoreCase);
DeviceAndScopeDic = new ConcurrentDictionary<string, Lazy<List<string>>>(StringComparer.OrdinalIgnoreCase);
CurrentScope = "default"; CurrentScope = "default";
} }