serial port thread locking while processing data read from serial port

删除回忆录丶 提交于 2020-01-24 21:35:26

问题


I have an event handler that gets called anytime data is received on a serial port, once this event is called I process an individual byte of data until all data is processed.

My question is, how do I make sure that this IBSerialPort_DataReceived event handler doesn't get called again asynchronously while I am stilling processing bytes from the first time it was called, ie I want to guarantee the ProcessByte method is only ever executing on one thread at a time.

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

回答1:


First read the documentation on the library you are using - can the event be raised asynchronously? If not then you are done.

UPDATE: Apparently this particular event cannot be raised concurrently, see Hans Passant's answer.

If it can, one strategy is to use a lock:

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

Take care now that you are using locks, if you lock on the same instance elsewhere you can get dead locks or if you hold the same lock for a while you will hold up processing...

Aside: generally the documentation will tell you if the event can raised concurrently so you will have to deal with re-entry, e.g. System.Threading.Timer's Tick event, though this is not always the case, e.g. the serverly lacking WinRT documentation on DatagramSocket's MessageReceived event.




回答2:


This is already interlocked inside the SerialPort class. There is an internal lock that ensures the DataReceived event cannot fire again if your event handler is still running.

You can see the relevant code in the Reference Source, I'll reproduce it here:

    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.
                }
            }
        }
    }

Note the lock (stream) statement in this code. You can also see that your DataReceived event handler won't be called unless something is received. And that you have to watch out for the SerialData.Eof event type, that has tripped up a fair number of programmers.

You don't have to help.



来源:https://stackoverflow.com/questions/20962084/serial-port-thread-locking-while-processing-data-read-from-serial-port

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!