SerialPort.DataRecive使用过程中的注意事项
.NET Framework中提供的串口操作类SerialPort已经用了很多年了,但是今天同事碰到一个问题,给我问住了。
我才发现用了这么多年的SerialPort还是有一些我所不知道的注意事项。
问题描述:同事在SerialPort的DataRecive绑定事件方法中,用了一个while循环,来处理串口接收缓冲区中的数据。但是同样的处理逻辑,放在不同的地方使用,发现不同的问题。
都是在DataRecive事件中,用while循环处理缓冲区数据,但是发现其中一个项目中,DataRecive事件会多次触发,而另一个项目中,会一直在第一次触发DataRecive事件中的while循环中转,不会触发第二次DataRecive事件。
然后搞笑的来了,我当时按照对事件最基本的运行机制的理解,解释说:事件的触发,无论前一次触发有没有完成,都不会影响第二次触发时的执行。所以一直在DataRecive中的while循环中转,肯定是有哪里影响了。
但是后来发现,我的判断错误了。
对于SerialPort中的DataRecive事件来说,前一次触发未完成时,是不会有第二次触发的。
后来反编译了一下SerialPort,证实了上述结论:
public void Open() { if (IsOpen) { throw new InvalidOperationException(SR.GetString("Port_already_open")); } new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); internalSerialStream = new SerialStream(portName, baudRate, parity, dataBits, stopBits, readTimeout, writeTimeout, handshake, dtrEnable, rtsEnable, discardNull, parityReplace); internalSerialStream.SetBufferSizes(readBufferSize, writeBufferSize); internalSerialStream.ErrorReceived += CatchErrorEvents; internalSerialStream.PinChanged += CatchPinChangedEvents; internalSerialStream.DataReceived += CatchReceivedEvents; }
private void CatchReceivedEvents(object src, SerialDataReceivedEventArgs e) { SerialDataReceivedEventHandler dataReceived = this.DataReceived; SerialStream serialStream = internalSerialStream; if (dataReceived == null || serialStream == null) { return; } lock (serialStream) { bool flag = false; try { flag = serialStream.IsOpen && (SerialData.Eof == e.EventType || BytesToRead >= receivedBytesThreshold); } catch { } finally { if (flag) { dataReceived(this, e); } } } }
从上面SerialPort的代码可以看出,对dataRecived事件的调用是加了锁的,也就是说,dataRecived事件如果没有执行完,那么后续是不会再次触发的。