multithreading - C# - How to hand off which thread reads from serial port? -
background
a customer asked me find out why c# application (we'll call xxx, delivered consultant has fled scene) flaky, , fix it. application controls measurement device on serial connection. device delivers continuous readings (which displayed on screen), , app needs stop continuous measurements , go command-response mode.
how not it
for continuous measurements, xxx uses system.timers.timer
background processing of serial input. when timer fires, c# runs timer's elapsedeventhandler
using thread pool. xxx's event handler uses blocking commport.readline()
several second timeout, calls delegate when useful measurement arrives on serial port. portion works fine, however...
when time stop realtime measurements , command device different, application tries suspend background processing gui thread setting timer's enabled = false
. of course, sets flag preventing further events, , background thread waiting serial input continues waiting. gui thread sends command device, , tries read reply – reply received background thread. background thread becomes confused not expected measurement. gui thread meanwhile becomes confused didn't receive command reply expected. know why xxx flaky.
possible method 1
in similar application, used system.componentmodel.backgroundworker
thread free-running measurements. suspend background processing did 2 things in gui thread:
- call
cancelasync
method on thread, and - call
commport.discardinbuffer()
, causes pending (blocked, waiting) comport read in background thread throwsystem.io.ioexception "the i/o operation has been aborted because of either thread exit or application request.\r\n"
.
in background thread catch exception , clean promptly, , works intended. unfortunately discardinbuffer
provoking exception in thread's blocking read not documented behavior anywhere can find, , hate relying on undocumented behavior. works because internally discardinbuffer
calls win32 api purgecomm, interrupts blocking read (documented behavior).
possible method 2
directly use baseclass stream.readasync
method, monitor cancellation token, using supported way of interrupting background io.
because number of characters received variable (terminated newline), , no readasyncline
method exists in framework, don't know if possible. process each character individually take performance hit (might not work on slow machines, unless of course line-termination bit implemented in c# within framework).
possible method 3
create lock "i've got serial port". nobody reads, writes, or discards input port unless have lock (including repeating blocking read in background thread). chop timeout values in background thread 1/4 second acceptable gui responsiveness without overhead.
question
does have proven solution deal problem? how can 1 cleanly stop background processing of serial port? i've googled , read dozens of articles bemoaning c# serialport
class, haven't found solution.
thanks in advance!
msdn article serialport
class states:
if
serialport
object becomes blocked during read operation, do not abort thread. instead, either close base stream or dispose ofserialport
object.
so best approach, point of view, second one, async
reading , step step checking line-ending character. you've stated, check each char big performance loss, suggest investigate readline
implementation ideas how perform faster. note use newline
property of serialport
class.
i want note there no readlineasync
method default as msdn states:
by default,
readline
method block until line received. if behavior undesirable, setreadtimeout
property non-zero value forcereadline
method throwtimeoutexception
if line not available on port.
so, may be, in wrapper can implement similar logic, task
cancel if there no line end in given time. also, should note this:
because
serialport
class buffers data, , stream contained inbasestream
property not, 2 might conflict how many bytes available read.bytestoread
property can indicate there bytes read, these bytes might not accessible stream contained inbasestream
property because have been bufferedserialport
class.
so, again, suggest implement wrapper logic asynchronous read , checking after each read, there line-end or not, should blocking, , wrap inside async
method, cancel task
after time.
hope helps.
Comments
Post a Comment