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:

  1. call cancelasync method on thread, and
  2. call commport.discardinbuffer(), causes pending (blocked, waiting) comport read in background thread throw system.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 of serialport 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, set readtimeout property non-zero value force readline method throw timeoutexception 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 in basestream property not, 2 might conflict how many bytes available read. bytestoread property can indicate there bytes read, these bytes might not accessible stream contained in basestream property because have been buffered serialport 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

Popular posts from this blog

php - Admin SDK -- get information about the group -

dns - How To Use Custom Nameserver On Free Cloudflare? -

Python Error - TypeError: input expected at most 1 arguments, got 3 -