【问题标题】:serial port communication accumulate big number of running threads串口通信累积大量运行线程
【发布时间】:2011-01-18 16:23:00
【问题描述】:

我们的串口通信有以下 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 框架不能正确处理他们的线程?还是我没有正确使用?

【问题讨论】:

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

标签: c# .net multithreading threadpool


【解决方案1】:

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

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

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

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

设置可以并发活动的线程池的请求数。在线程池线程可用之前,所有高于该数量的请求都会排队。

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-14
      • 2015-10-31
      • 2012-09-24
      • 1970-01-01
      • 2017-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多