C# 串口通信积累了大量正在运行的线程

C# 串口通信积累了大量正在运行的线程,c#,.net,multithreading,threadpool,C#,.net,Multithreading,Threadpool,我们有以下用于串行端口通信的C#代码: ProcCntrlSSPort = new SerialPort(portNumber, 115200, Parity.None, 8, StopBits.One); ProcCntrlSSPort.Handshake = Handshake.None; ProcCntrlSSPort.ReadTimeout = 10; Proc

我们有以下用于串行端口通信的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作为接收的字节阈值,因为我们的一个重要数据每次发送1字节,只要该字节可用

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

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

出于测试目的,我增加了接收字节数的阈值,即128。这将减缓累积,但线程数仍会缓慢增加。为什么.net framework不能正确处理线程?或者我没有正确使用它?

解释了可能发生的情况

看起来DataReceived调用将使用ThreadPool并调用QueueUserWorkItem。这意味着如果你处理数据的速度不够快,电话可能会像你看到的那样排队

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

看起来还可以使用设置线程池中创建的最大线程数

设置可同时处于活动状态的对线程池的请求数。在线程池线程可用之前,所有超过该数目的请求都将保持排队状态


但这一切将改变排队的地点。最终,您必须解决它落后的原因。

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


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

Ummm。听起来并不聪明,但正确地处理这些问题并不取决于.NET框架,而是取决于开发人员。我们有一个扫描应用程序,每天通过串行端口处理数千张优惠券,没有问题。您是否正确研究了与.NET的串行端口通信,以便了解您正在做什么和正在发生什么?线程是复杂的,你不能期望在不了解它的情况下就这样做,就像你不学习交通规则就可以在大城市安全驾驶汽车一样。你是说你在
ProcCntrlSSPortDataReceived
函数中创建线程?你能把你在那里做的事情贴出来吗?问题可能是您在哪里创建线程。我们没有使用自己的线程来处理串行端口。这就是.Net的SerialPort类创建线程来处理串行端口,我想。@SwDevMan81,我们在ProcCntrlSSPortDataReceived中没有线程。我们假设只要数据可用,.Net的SerialPort类就会调用该方法。我将撤回上面的注释,但为了真正了解发生了什么,我需要查看整个代码,现在我没有时间来查看它@SwDevMan81关于“在何处创建线程”的说法可能是正确的,即使您没有显式地创建线程。DataReceived事件自动发生在另一个线程上。线程将在超出范围时终止并释放。很可能存在代码组织问题,即将某些变量附加到作用域中的线程,这样线程就永远无法关闭。(更多信息)