public override void StopStreaming()
comPort.DataReceived -= comPort_DataReceived;
Thread.Sleep(1000);
comPort.DiscardInBuffer();
Thread.Sleep(1000);
comPort.Close();
isStreaming = false;
It seems to work now but I'm not really that happy. I wish there was a more effective way to remove the callback rather than inserting sleep periods in the program.
–
Your DataReceived event handler is called on a threadpool thread. And yes, they've got the awkward habit of running your code at an unpredictable time, it is not instant. So it is fairly inevitable that, if the device is actively sending data, that it can race with your Close() call and run after you closed it. Unsubscribing doesn't fix it, the threadpool thread already got its target method.
Do realize what you are doing to trigger this problem, you are closing the port while the device is sending data. That's not great, it is guaranteed to cause data loss. But not unlikely to happen when you are debugging your code since you don't actually care about the data.
A counter-measure is to turn off handshaking so the device cannot send anything anymore. Discard the input buffer. Then sleep for a while, a second or two, to ensure that any threadpool threads in-flight have completed running. Then close the port. A very pragmatic one is to simply not close the port, Windows will take care of it when your process terminates.
–
–
–
Looks like multi-threading issue.
SerialPort.DataReceived
is raised in a worker thread from thread pool. You're closing port from the thread, that differs from the thread, where SerialPort.DataReceived
raised in.
You can handle InvalidOperationException
or write some synchronization code to solve this problem.
Update.
The problem is that if your devices sends data intensively, SerialPort
queues more and more work items to thread pool. Even if your code will sleep any time before Close
, it can be not enough. Unfortunately, SerialPort
has an ugly implementation. It hasn't an option, which could tell "please, stop spam me with your data".
Hence, the concrete solution depends on device's protocol and handshaking parameters.
–
–
I had the same problem in an application I've been working on. It's exciting to read here about how the threadpool can bring it about.
Before I tracked down it's source though, I found that enclosing the contents of the DataReceived event handler in a try
catch
statement written in anticipation of the problem was a very effective way to solve it. Now that I know there's not really anything I can do to prevent the issue if I need/want to close a SerialPort while still receiving data, I'm quite happy with this approach.
I had similar issue when the user attempted to Exit application whilst it was still receiving data from the connected device. Application was throwing a System.IO.IOException following call to Me.Close().
Simplest solution I found was to set the SerialPort ReceivedBytesThreshold to a large number in the _FormClosing event handler. This reduces the frequency of DataReceived events and provides time for the Close() call to complete whilst the DataReceived event handler is inactive.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.