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
+17 -12
View File
@@ -2,6 +2,7 @@
using NModbus;
using NModbus.Serial;
using System;
using System.Collections.Concurrent;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;
@@ -10,14 +11,18 @@ namespace DeviceCommand.Flexible
{
/// <summary>
/// 灵活型 Modbus RTU 串口通信类(免实例化,每次调用临时创建串口连接)。
/// 支持保持寄存器与线圈的读写操作,内部使用通信锁保证同一时刻只有一个事务在执行,
/// 适用于偶发性、无需保持长连接的 Modbus RTU 设备读写场景。
/// 支持保持寄存器与线圈的读写操作,内部使用按串口名称粒度的通信锁保证同一串口同一时刻只有一个事务在执行,
/// 不同串口之间互不阻塞,适用于偶发性、无需保持长连接的 Modbus RTU 设备读写场景。
/// </summary>
[ADPCommand]
public static class FModbusRTU
{
// 通信锁:保证同一时刻只有一个 Modbus 事务在执行
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>
/// 创建串口实例并配置超时参数。
@@ -76,7 +81,7 @@ namespace DeviceCommand.Flexible
int writeTimeout = 3000,
CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
await GetLock(portName).WaitAsync(ct);
try
{
using var port = CreatePort(
@@ -96,7 +101,7 @@ namespace DeviceCommand.Flexible
}
finally
{
_commLock.Release();
GetLock(portName).Release();
}
}
@@ -127,7 +132,7 @@ namespace DeviceCommand.Flexible
int writeTimeout = 3000,
CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
await GetLock(portName).WaitAsync(ct);
try
{
using var port = CreatePort(
@@ -147,7 +152,7 @@ namespace DeviceCommand.Flexible
}
finally
{
_commLock.Release();
GetLock(portName).Release();
}
}
@@ -183,7 +188,7 @@ namespace DeviceCommand.Flexible
int writeTimeout = 3000,
CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
await GetLock(portName).WaitAsync(ct);
try
{
using var port = CreatePort(
@@ -203,7 +208,7 @@ namespace DeviceCommand.Flexible
}
finally
{
_commLock.Release();
GetLock(portName).Release();
}
}
@@ -234,7 +239,7 @@ namespace DeviceCommand.Flexible
int writeTimeout = 3000,
CancellationToken ct = default)
{
await _commLock.WaitAsync(ct);
await GetLock(portName).WaitAsync(ct);
try
{
using var port = CreatePort(
@@ -254,7 +259,7 @@ namespace DeviceCommand.Flexible
}
finally
{
_commLock.Release();
GetLock(portName).Release();
}
}