串口通信积累大量运行线程
我们的串行端口通信具有以下 C# 代码:
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;
try
{
ProcCntrlSSPort.Open();
ProcCntrlSSPort.DiscardInBuffer();
}
每 100 毫秒,我们的应用程序就会收到一条状态消息。据我了解,当 SerialPort
收到 ReceivedBytesThreshold
字节数时,SerialPort
将触发一个事件。我们必须使用 1 作为 ReceivedBytesThreshold ,因为只要该字节可用,我们的重要数据就会每次发送 1 个字节。
当 SerialPort 触发事件并由接收器处理该事件时,应处理该事件,并且与该事件关联的线程应可供下次使用。所以不应该有大量的运行线程积累。
但我发现一夜之间运行的线程会不断从20个线程增加到400多个线程。只是状态消息发送到我们的应用程序,然后没有其他活动。 我已经禁用了所有进程代码,因此我确信累积的线程不是来自我们的代码。这意味着我们出于测试目的不对接收到的数据执行任何操作。
出于测试目的,我增加了 ReceivedBytesThreshold
,即 128。它会减慢积累速度,但线程数仍然会缓慢上升。为什么.net框架无法正确处理它们的线程?还是我没有正确使用?
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;
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
SerialPort 如何处理 DataReceived 解释可能发生的情况。
看起来 DataReceived 调用将使用 ThreadPool 并调用 QueueUserWorkItem。这意味着,如果您处理数据的速度不够快,调用可能会像您所看到的那样排队。
如果您希望保持倒计时(作为测试),您可以尝试在收到事件后使用 BytesToRead 读出所有字节,然后“处理”读取的每个字符。帖子中建议的另一个选项是创建您自己的“处理”线程,以便在收到数据时进行处理。
看起来您还可以使用 ThreadPool.SetMaxThreads
但这一切只会改变排队的地点。最终你必须解决它落后的原因。
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
But this all this would do is change where the queuing is taking place. Ultimately you have to fix why its getting behind.
正如 SwDevMan81 所说,DataReceived(与 .NET 中的许多其他异步事件一样)是在 ThreadPool 线程中触发的。有几件事你不应该在 ThreadPool 线程中做,最重要的是: 不要等待任何事情,即不要使用阻塞文件操作,不要使用 WaitForSingleObject,不要使用 ISynchronizeInvoke.Invoke,除非你确保它不会阻塞(长时间)。否则,当新的工作项排队时,ThreadPool 将简单地启动一个新线程,直到达到 ThreadPool.MaxThreads 限制(该限制高得离谱,IIRC)。
确定这是否是您的问题的最简单方法是查看 ThreadPool.GetAvailableThreads - 如果它随着时间的推移而减少,那么您可能应该编写自己的线程来处理数据,并将其放入 ProcCntrlSSPortDataReceived 中的线程安全队列中。
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.