近期小细节总结
串口并发调用
单个串口通讯(Modbus RTU也算),业务流程中的串口调用,既有定时轮询又有依次发送,也就是涉及到并发调用通讯的,不要犹豫,为通讯管理模块建立消息队列
-
不用纠结锁的问题,天然线程安全
-
定时任务和手动操作随便调用,自动排队
// 请求队列 private readonly Channel<ModbusRequest> _requestChannel = Channel.CreateBounded<ModbusRequest>(20); private readonly CancellationTokenSource _processingCts = new CancellationTokenSource(); private Task _processingTask; // 添加请求类 private class ModbusRequest { public byte DeviceAddress { get; set; } public byte FunctionCode { get; set; } public ushort RegisterAddress { get; set; } public ushort Value { get; set; } public ushort RegisterCount { get; set; } public TaskCompletionSource<byte[]> CompletionSource { get; set; } } // 启动请求处理任务 _processingTask = Task.Run(ProcessModbusRequests); /// <summary> /// Modbus命令内部实现(无锁版本) /// </summary> private async Task<byte[]> SendModbusCommandInternal(byte deviceAddress, byte functionCode, ushort registerAddress, ushort value = 0, ushort registerCount = 1) { try { // 构建请求帧(原SendModbusCommand的逻辑移到这里) byte[] request; if (functionCode == 0x03) // 读取保持寄存器 { request = new byte[6]; request[0] = deviceAddress; request[1] = functionCode; request[2] = (byte)(registerAddress >> 8); request[3] = (byte)(registerAddress & 0xFF); request[4] = (byte)(registerCount >> 8); request[5] = (byte)(registerCount & 0xFF); } else if (functionCode == 0x06) // 写单个寄存器 { request = new byte[6]; request[0] = deviceAddress; request[1] = functionCode; request[2] = (byte)(registerAddress >> 8); request[3] = (byte)(registerAddress & 0xFF); request[4] = (byte)(value >> 8); request[5] = (byte)(value & 0xFF); } else { throw new ArgumentException($"不支持的功能码: {functionCode}"); } // 添加CRC校验 byte[] crc = CalculateCRC(request); byte[] fullRequest = new byte[request.Length + 2]; Array.Copy(request, fullRequest, request.Length); fullRequest[request.Length] = crc[0]; fullRequest[request.Length + 1] = crc[1]; // 清空缓冲区 _serialPort.DiscardInBuffer(); _serialPort.DiscardOutBuffer(); // 发送请求 IoC.Get<MessageManagement>().AddMessage($"Write: {BitConverter.ToString(fullRequest).Replace("-", " ")}"); _serialPort.Write(fullRequest, 0, fullRequest.Length); // 异步读取响应 return await ReadModbusResponse(); } catch (Exception ex) { IoC.Get<MessageManagement>().AddMessage($"Modbus通信失败: {ex.Message}", MessageType.警告); return null; } } /// <summary> /// 异步读取Modbus响应 /// </summary> private async Task<byte[]> ReadModbusResponse() { await Task.Delay(500); // 等待设备响应 List<byte> response = new List<byte>(); DateTime startTime = DateTime.Now; while (DateTime.Now - startTime < TimeSpan.FromMilliseconds(READ_TIMEOUT)) { if (_serialPort.BytesToRead > 0) { byte[] buffer = new byte[_serialPort.BytesToRead]; int bytesRead = _serialPort.Read(buffer, 0, buffer.Length); response.AddRange(buffer.Take(bytesRead)); // 检查是否收到完整帧 if (response.Count >= 5) // 最小响应长度 { // 验证CRC byte[] receivedData = response.ToArray(); byte[] receivedCRC = new byte[] { receivedData[receivedData.Length - 2], receivedData[receivedData.Length - 1] }; byte[] calculatedCRC = CalculateCRC(receivedData.Take(receivedData.Length - 2).ToArray()); if (receivedCRC[0] == calculatedCRC[0] && receivedCRC[1] == calculatedCRC[1]) { return receivedData; } else { IoC.Get<MessageManagement>().AddMessage($"CRC error: {BitConverter.ToString(receivedData).Replace("-", " ")}"); } } } await Task.Delay(10); } throw new TimeoutException("读取响应超时"); } /// <summary> /// 发送Modbus命令(队列版本) /// </summary> private async Task<byte[]> SendModbusCommand(byte deviceAddress, byte functionCode, ushort registerAddress, ushort value = 0, ushort registerCount = 1) { var request = new ModbusRequest { DeviceAddress = deviceAddress, FunctionCode = functionCode, RegisterAddress = registerAddress, Value = value, RegisterCount = registerCount, CompletionSource = new TaskCompletionSource<byte[]>() }; // 修复:使用带CancellationToken的WaitToWriteAsync if (await _requestChannel.Writer.WaitToWriteAsync(_processingCts.Token)) { await _requestChannel.Writer.WriteAsync(request, _processingCts.Token); // 使用带超时的Task等待 using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); var timeoutTask = Task.Delay(Timeout.Infinite, timeoutCts.Token); var responseTask = request.CompletionSource.Task; var completedTask = await Task.WhenAny(responseTask, timeoutTask); if (completedTask == responseTask) { return await responseTask; } else { throw new TimeoutException("Modbus操作超时"); } } else { throw new TimeoutException("Modbus请求队列已满"); } } /// <summary> /// 读取保持寄存器 /// </summary> async private Task<ushort[]> ReadHoldingRegisters(byte deviceAddress, ushort startAddress, ushort registerCount) { byte[] response = await SendModbusCommand(deviceAddress, 0x03, startAddress, 0, registerCount); if (response != null && response.Length >= 5 + registerCount * 2) { ushort[] result = new ushort[registerCount]; for (int i = 0; i < registerCount; i++) { int offset = 3 + i * 2; result[i] = (ushort)((response[offset] << 8) | response[offset + 1]); } return result; } return null; } /// <summary> /// 写单个寄存器 /// </summary> async private Task<bool> WriteSingleRegister(byte deviceAddress, ushort registerAddress, ushort value) { byte[] response = await SendModbusCommand(deviceAddress, 0x06, registerAddress, value); return response != null && response.Length >= 6; }
CPU占用
减少Task.Factory.StartNew,线程池都给干满了,非必要不要用

浙公网安备 33010602011771号