diff --git a/UIShare/GlobalVariable/DeviceManager.cs b/UIShare/GlobalVariable/DeviceManager.cs
index 7eaaf67..3202aa8 100644
--- a/UIShare/GlobalVariable/DeviceManager.cs
+++ b/UIShare/GlobalVariable/DeviceManager.cs
@@ -19,6 +19,7 @@ namespace UIShare.GlobalVariable
{
private object _lockObj = new object();
public SystemConfig _systemConfig { get; set; }
+ private readonly GlobalInfo _globalInfo;
/// 按 DeviceName 索引的设备字典,便于业务层按名取实例。
public IDictionary DeviceMap { get; private set; }
@@ -27,11 +28,33 @@ namespace UIShare.GlobalVariable
/// 类名 → Type 的反射缓存(仅扫描一次)。
private static readonly IReadOnlyDictionary _deviceTypeMap = BuildDeviceTypeMap();
- public DeviceManager(SystemConfig systemConfig)
+ public DeviceManager(SystemConfig systemConfig, GlobalInfo globalInfo)
{
_systemConfig = systemConfig;
+ _globalInfo = globalInfo;
InitDevices();
}
+ ///
+ /// 根据设备配置提取唯一的硬件指纹字符串。
+ /// Tcp → "Tcp:IP:Port";Serial → "Serial:PortName";无法识别则返回空字符串。
+ ///
+ private static string ExtractHardwareFingerprint(DeviceInfoVM config)
+ {
+ if (string.Equals(config.ConnectionType, "Tcp", StringComparison.OrdinalIgnoreCase)
+ && config.TcpConfig != null)
+ {
+ return $"Tcp:{config.TcpConfig.IPAddress}:{config.TcpConfig.Port}";
+ }
+
+ if (string.Equals(config.ConnectionType, "Serial", StringComparison.OrdinalIgnoreCase)
+ && config.SerialPortConfig != null)
+ {
+ return $"Serial:{config.SerialPortConfig.PortName}";
+ }
+
+ return string.Empty;
+ }
+
private void InitDevices()
{
DeviceMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
@@ -51,24 +74,41 @@ namespace UIShare.GlobalVariable
try
{
- IBaseInterface? instance = config.ConnectionType switch
+ // 第一步:提取硬件指纹,为空则跳过
+ var fingerprint = ExtractHardwareFingerprint(config);
+ if (string.IsNullOrEmpty(fingerprint))
{
- "Tcp" => CreateTcpDevice(deviceType, config.TcpConfig),
- "Serial" => CreateSerialDevice(deviceType, config.SerialPortConfig),
- _ => null
- };
+ LoggerHelper.Warn($"设备 [{config.DeviceName}] 无法提取硬件指纹(连接方式={config.ConnectionType}),已跳过。");
+ continue;
+ }
+
+ // 第二步:原子化获取或添加 Lazy 包装盒,确保同一指纹全局只创建一个实例
+ var lazy = _globalInfo.HardwarePool.GetOrAdd(fingerprint, key => new Lazy(() =>
+ {
+ return config.ConnectionType switch
+ {
+ "Tcp" => CreateTcpDevice(deviceType, config.TcpConfig)!,
+ "Serial" => CreateSerialDevice(deviceType, config.SerialPortConfig)!,
+ _ => null!
+ };
+ }));
+
+ // 第三步:安全拆盒,Lazy 内部线程锁保证只实例化一次
+ var instance = lazy.Value;
if (instance == null)
{
LoggerHelper.Warn($"设备 [{config.DeviceName}] 连接方式 [{config.ConnectionType}] 不支持,已跳过。");
continue;
}
+
+ // 第四步:绑定逻辑名 → 同一物理设备可被多个台架名称映射
if (!string.IsNullOrWhiteSpace(config.DeviceName))
{
DeviceMap[config.DeviceName] = instance;
}
- LoggerHelper.Info($"已加载设备 [{config.DeviceName} / {config.DeviceType} / {config.ConnectionType}]");
+ LoggerHelper.Info($"已加载设备 [{config.DeviceName} / {config.DeviceType} / {config.ConnectionType}] 指纹={fingerprint}");
}
catch (Exception ex)
{
diff --git a/UIShare/GlobalVariable/GlobalInfo.cs b/UIShare/GlobalVariable/GlobalInfo.cs
index ab5fc5c..fde936c 100644
--- a/UIShare/GlobalVariable/GlobalInfo.cs
+++ b/UIShare/GlobalVariable/GlobalInfo.cs
@@ -1,4 +1,6 @@
-using System;
+using DeviceCommand.Base;
+using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -13,6 +15,10 @@ namespace UIShare.GlobalVariable
public Dictionary StepRunningDic { get; set; }
public Dictionary ConfigDic { get; set; }
public Dictionary ScopeDic { get; set; }
+
+ /// 硬件指纹 → 设备实例的并发池,确保同一物理硬件全局只创建一个驱动实例。
+ public ConcurrentDictionary> HardwarePool { get; set; }
+
public String UserName { get; set; } = "Not Logged in";
public bool IsAdmin { get; set; } = true;
public string CurrentOpeningScope;
@@ -35,6 +41,7 @@ namespace UIShare.GlobalVariable
StepRunningDic = new();
ConfigDic = new();
ScopeDic = new();
+ HardwarePool = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase);
CurrentScope = "default";
}