serial port communication accumulate big number of running threads
We have the follow C# code for our serial port communication:
ProcCntrlSSPort = new SerialPort(portNumber, 115200, Parity.None, 8, StopBits.One);
ProcCntrlSSPort.Handshake = Handshake.None;
ProcCntrlSSPort.ReadTimeout = 10;
ProcCntrlSSPort.ReadBufferSize = 32768;
ProcCntrlSSPort.DataReceived += ProcCntrlSSPortDataReceived;
//ProcCntrlSSPort.DataReceived += new SerialDataReceivedEventHandler(ProcCntrlSSPortDataReceived);
ProcCntrlSSPort.ReceivedBytesThreshold = 1;
开发者_Go百科 try
{
ProcCntrlSSPort.Open();
ProcCntrlSSPort.DiscardInBuffer();
}
Every 100 msec, there is a status message received by our application. I understand when the SerialPort
received ReceivedBytesThreshold
number of bytes, an event will be fired by the SerialPort
. We have to use 1 for the ReceivedBytesThreshold
because one of our important data is sent 1 byte each time whenever that byte is available.
When an event is fired by SerialPort and is processed by the receiver, that event should be disposed and the thread associated that event should be available for next use. so there should not be a big number of running thread accumulation.
But I found the running threads will continuously increase from 20 threads up to more than 400 threads after overnight. Just status message is sent to our application, no other activities then. I have disabled all process code so I am sure the accumulated threads are NOT from our code. That means we do nothing on the received data for the testing purpose.
I have increased the ReceivedBytesThreshold
, saying 128, for testing purpose. It will slow down the accumulation but the thread count still goes up slowly. why .net framework cannot handle their threads properly? Or I didn't use it correctly?
How does SerialPort handle DataReceived explains what might be happening.
Looks like the DataReceived calls will use the ThreadPool and calls to QueueUserWorkItem. This means that if you dont process the data fast enough, the calls could be queuing up like you are seeing.
If you wish to keep the count down (as a test), you could try and read out all the bytes once you receive the event using BytesToRead
and then 'process' each character read. Another option that is suggested in the post is to create a "processing" thread of your own to do the processing when you receive the data.
It also looks like you can set the maximum number of threads created in the ThreadPool using ThreadPool.SetMaxThreads
Sets the number of requests to the thread pool that can be active concurrently. All requests above that number remain queued until thread pool threads become available.
But this all this would do is change where the queuing is taking place. Ultimately you have to fix why its getting behind.
As SwDevMan81 said, DataReceived (like many other asynchronous events in .NET) is fired in a ThreadPool thread. There are a few things you shouldn't do in ThreadPool threads, most importantly: Don't wait for anything, i.e. don't use blocking file operations, don't use WaitForSingleObject, don't use ISynchronizeInvoke.Invoke unless you're sure it won't block (for long). Otherwise, the ThreadPool will simply start a new thread when a new work item is enqueued, until it hits the ThreadPool.MaxThreads limit (which is ridiculously high, IIRC).
The simplest way to find out if that's your problem is to look at ThreadPool.GetAvailableThreads - if it decreases over time, then you should maybe write your own thread to process the data and just put it into a thread-safe queue in ProcCntrlSSPortDataReceived.
精彩评论