简体   繁体   中英

C# Serial DataReceived event starved

I am building on top of an existing application and using the C# SerialPort class to handle data transactions over USB. I've noticed that when the application spawns a number of long-running threads and does not specify them as long-running using the TaskCreation LongRunning option, these threads can temporarily starve the SerialPort DataReceived event and prevent it from triggering for some extended amount of time.

Is this some fundamental result of the way in which C# handles thread management?

Is there any way to increase the "priority" of the DataReceived event?

If not, would a "solution" be to have a constantly running thread that polls the serial port data flags rather than using the DataReceived event?

Thanks!

That is pretty fundamental, yes. Your DataReceived event handler is called by a thread-pool thread. When you've got too many of them active for other purposes, like Tasks that are not LongRunning, then it can be a while before your event handler gets a shot at running. The normal operating system scheduling algorithm that boosts a thread's priority when it completes an I/O call is ineffective here, it only gets the tp thread scheduled efficiently :)

This is a fundamental fire-hose problem, you are expecting the machine to accomplish more work than it can perform. The ballpark way to know if you are doing it right is by looking at Task Manager. CPU usage should be pegged at 100%. If it is substantially less then you are not using the thread-pool efficiently, some tasks are hogging the pool but are not executing enough code, typically because they are waiting too much on a sync object or an I/O operation to complete. You ought to fix that, either by using a plain Thread or with TaskCreationOptions.LongRunning. ThreadPool.SetMinThreads() is often quoted as a quick fix, it is a dirty one. Upgrading the machine spec, more cores, is a cleaner one.

There's an even simpler solution -- use the serial port the way the device driver writers intended. There is absolutely nothing about serial port communications that warrants use of a worker thread, either manually created or from the thread pool. I encourage you to read my entire blog post "If you must use .NET System.IO.Ports.SerialPort" , but the short version is to use BaseStream.ReadAsync with async + await if you are on a recent version of .NET, and BaseStream.BeginRead with a callback otherwise.

Also, thanks for providing me with yet another reason the DataReceived event is horrible. The list is getting quite long.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM