P2: Flexible四类通信锁从全局静态改为按端口/IP粒度(ConcurrentDictionary),不同物理端口互不阻塞

This commit is contained in:
2026-09-14 13:53:46 +08:00
parent 8d8df56544
commit 7043a66a28
4 changed files with 62 additions and 42 deletions
+13 -8
View File
@@ -1,5 +1,6 @@
using Common.Attributes;
using System;
using System.Collections.Concurrent;
using System.IO.Ports;
using System.Text;
using System.Threading;
@@ -10,14 +11,18 @@ namespace DeviceCommand.Flexible
/// <summary>
/// 灵活型串口通信类(免实例化,每次调用临时创建串口连接)。
/// 支持只发送指令、发送并读取应答两种最常用操作,
/// 内部使用通信锁保证同一时刻只有一个串口事务在执行,
/// 适用于偶发性、无需保持长连接的串口设备通信场景(如示波器、电源的 SCPI 指令)。
/// 内部使用按串口名称粒度的通信锁保证同一串口同一时刻只有一个事务在执行,
/// 不同串口之间互不阻塞,适用于偶发性、无需保持长连接的串口设备通信场景(如示波器、电源的 SCPI 指令)。
/// </summary>
[ADPCommand]
public static class FSerialPort
{
// 通信锁:保证同一时刻只有一个串口事务在执行
private static readonly SemaphoreSlim _commLock = new(1, 1);
// 按串口名称粒度的通信锁:同一串口同一时刻只有一个事务在执行,不同串口互不阻塞
private static readonly ConcurrentDictionary<string, SemaphoreSlim> _commLocks = new();
/// <summary>获取指定串口的通信锁(不存在则自动创建)</summary>
private static SemaphoreSlim GetLock(string portName)
=> _commLocks.GetOrAdd(portName, _ => new SemaphoreSlim(1, 1));
/// <summary>
/// 创建串口实例并配置 UTF8 编码与超时参数。
@@ -48,7 +53,7 @@ namespace DeviceCommand.Flexible
/// <param name="ct">异步取消令牌</param>
public static async Task (string portName,int baudRate,Parity parity,int dataBits,StopBits stopBits,int sendTimeout,int receiveTimeout,string command,CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
await GetLock(portName).WaitAsync(ct);
try
{
using var port = CreatePort(
@@ -66,7 +71,7 @@ namespace DeviceCommand.Flexible
}
finally
{
_commLock.Release();
GetLock(portName).Release();
}
}
@@ -90,7 +95,7 @@ namespace DeviceCommand.Flexible
/// <returns>去除结束符并去除首尾空白后的应答字符串</returns>
public static async Task<string> (string portName,int baudRate, Parity parity, int dataBits, StopBits stopBits,int sendTimeout, int receiveTimeout,string command,string delimiter = "\n", CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
await GetLock(portName).WaitAsync(ct);
try
{
using var port = CreatePort(
@@ -131,7 +136,7 @@ namespace DeviceCommand.Flexible
}
finally
{
_commLock.Release();
GetLock(portName).Release();
}
}