【问题标题】:serial port thread locking while processing data read from serial port处理从串口读取的数据时串口线程锁定
【发布时间】:2014-01-24 13:43:56
【问题描述】:

我有一个事件处理程序,只要在串行端口上接收到数据,就会调用它,一旦调用此事件,我就会处理一个单独的数据字节,直到处理完所有数据。

我的问题是,我如何确保这个 IBSerialPort_DataReceived 事件处理程序不会再次被异步调用,而我正在从第一次调用它开始处理字节,即我想保证 ProcessByte 方法只执行一次一个线程。

void IBSerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
  while (BytesToRead > 0)
  {
    ProcessByte((byte)ReadByte());
  }
}

【问题讨论】:

标签: c# multithreading asynchronous serial-port locks


【解决方案1】:

首先阅读您正在使用的库的文档 - 可以异步引发事件吗?如果没有,那么你就完成了。

更新:显然这个特定事件不能同时引发,请参阅 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 事件,尽管并非总是如此,例如服务器在DatagramSocketMessageReceived 事件中缺少WinRT 文档。

【讨论】:

    【解决方案2】:

    这已经在 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 事件类型,这让相当多的程序员感到不安。

    你不必帮忙。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多