串口通信累积大量运行线程

时间:2011-01-18 16:23:00

标签: c# .net multithreading threadpool

我们的串口通信遵循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会触发一个事件。我们必须为ReceivedBytesThreshold使用1,因为每当该字节可用时,我们的一个重要数据每次发送1个字节。

当SerialPort触发事件并由接收者处理时,应该处理该事件,并且该事件的线程应该可供下次使用。所以不应该有大量的运行线程积累。

但是我发现在过夜之后,正在运行的线程将从20个线程连续增加到超过400个线程。只是状态消息被发送到我们的应用程序,然后没有其他活动。 我已禁用所有进程代码,因此我确信累积的线程不是来自我们的代码。这意味着我们对收到的数据不做任何测试。

为了测试目的,我增加了ReceivedBytesThreshold,说128。它会减慢积累,但线程数仍然会缓慢上升。为什么.net框架无法正确处理其线程?或者我没有正确使用它?

2 个答案:

答案 0 :(得分:2)

How does SerialPort handle DataReceived解释了可能发生的事情。

看起来DataReceived调用将使用ThreadPool并调用QueueUserWorkItem。这意味着如果你没有足够快地处理数据,那么呼叫可能会像你看到的那样排队。

如果您希望保持倒计时(作为测试),您可以尝试在使用BytesToRead接收事件后读出所有字节,然后“处理”每个字符读取。在帖子中建议的另一个选项是创建自己的“处理”线程,以便在收到数据时进行处理。

看起来您可以使用ThreadPool.SetMaxThreads设置在ThreadPool中创建的最大线程数

  

设置可以同时处于活动状态的线程池的请求数。高于该数字的所有请求将保持排队,直到线程池线程可用。

但是,所有这一切都会改变排队的位置。最终你必须解决它落后的原因。

答案 1 :(得分:1)

正如SwDevMan81所说,DataReceived(与.NET中的许多其他异步事件一样)是在ThreadPool线程中触发的。你不应该在ThreadPool线程中做一些事情,最重要的是:不要等待任何事情,即不要使用阻塞文件操作,不要使用WaitForSingleObject,不要使用ISynchronizeInvoke.Invoke除非你是确定它不会阻塞(长时间)。否则,ThreadPool将在新工作项入队时启动一个新线程,直到它达到ThreadPool.MaxThreads限制(非常高,IIRC)。

找出问题的最简单方法是查看ThreadPool.GetAvailableThreads - 如果它随着时间的推移而减少,那么您应该编写自己的线程来处理数据并将其放入线程安全的队列中ProcCntrlSSPortDataReceived。