我有一个事件处理程序,只要在一个串口上收到数据就会被调用,一旦调用了这个事件,我处理一个单独的数据字节,直到处理好所有数据。
我的问题是,我如何确保在第一次调用字节时我不会异步调用此IBSerialPort_DataReceived事件处理程序,即我想保证ProcessByte方法只执行在一个线程上一次。
void IBSerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
while (BytesToRead > 0)
{
ProcessByte((byte)ReadByte());
}
}
答案 0 :(得分:4)
这已经在SerialPort类中互锁。有一个内部锁,可确保在事件处理程序仍在运行时,DataReceived事件无法再次触发。
您可以在Reference Source中看到相关代码,我将在此处重现:
private void CatchReceivedEvents(object src, SerialDataReceivedEventArgs e)
{
SerialDataReceivedEventHandler eventHandler = DataReceived;
SerialStream stream = internalSerialStream;
if ((eventHandler != null) && (stream != null)){
lock (stream) {
// SerialStream might be closed between the time the event runner
// pumped this event and the time the threadpool thread end up
// invoking this event handler. The above lock and IsOpen check
// ensures that we raise the event only when the port is open
bool raiseEvent = false;
try {
raiseEvent = stream.IsOpen && (SerialData.Eof == e.EventType || BytesToRead >= receivedBytesThreshold);
}
catch {
// Ignore and continue. SerialPort might have been closed already!
}
finally {
if (raiseEvent)
eventHandler(this, e); // here, do your reading, etc.
}
}
}
}
请注意此代码中的lock (stream)
语句。您还可以看到,除非收到某些内容,否则不会调用您的DataReceived事件处理程序。而且你必须注意SerialData.Eof事件类型,这会使相当多的程序员绊倒。
你没有帮助。
答案 1 :(得分:2)
首先阅读您正在使用的库的文档 - 可以异步引发事件吗?如果没有,那么你就完成了。
更新:显然这个特殊事件不能同时提出,请参阅Hans Passant的回答。
如果可以,一种策略是使用lock
:
object myLock = new object();
void IBSerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
lock(myLock)
{
while (BytesToRead > 0)
{
ProcessByte((byte)ReadByte());
}
}
}
现在注意你正在使用锁,如果你锁定在其他地方的同一个实例,你可以获得死锁,或者如果你持有相同的锁一段时间,你将会阻止处理......
除此之外:通常文档会告诉您事件是否可以同时引发,因此您必须处理重新输入,例如System.Threading.Timer
的Tick事件,但情况并非总是如此,例如在DatagramSocket
的{{3}}事件中服务器缺乏WinRT文档。