последовательный порт связи накапливает большое количество запущенных потоков - PullRequest
1 голос
/ 18 января 2011

У нас есть следующий код 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 Framework не может правильно обрабатывать их потоки? Или я не правильно его использовал?

Ответы [ 2 ]

2 голосов
/ 18 января 2011

Как SerialPort обрабатывает DataReceived объясняет, что может происходить.

Похоже, что вызовы DataReceived будут использовать ThreadPool и вызовы QueueUserWorkItem. Это означает, что если вы не обрабатываете данные достаточно быстро, вызовы могут стоять в очереди, как вы видите.

Если вы хотите уменьшить счет (в качестве теста), вы можете попробовать прочитать все байты, как только получите событие, используя BytesToRead, а затем «обработать» каждый прочитанный символ. Другой вариант, который предлагается в публикации, - это создать собственную ветку «обработка», чтобы выполнять обработку при получении данных.

Похоже, вы также можете установить максимальное количество потоков, созданных в ThreadPool, используя ThreadPool.SetMaxThreads

Устанавливает количество запросов к пулу потоков, которые могут быть активны одновременно. Все запросы выше этого числа остаются в очереди, пока потоки пула потоков не станут доступными.

Но это все, что нужно сделать, это изменить место, где происходит очередь. В конечном счете, вы должны выяснить, почему он отстает.

1 голос
/ 18 января 2011

Как сказал SwDevMan81, DataReceived (как и многие другие асинхронные события в .NET) запускается в потоке ThreadPool.Есть несколько вещей, которые вы не должны делать в потоках ThreadPool, наиболее важно: не ждите ничего, то есть не используйте блокировку файловых операций, не используйте WaitForSingleObject, не используйте ISynchronizeInvoke.Invoke, если вы неуверен, что он не будет блокировать (надолго).В противном случае ThreadPool просто запустит новый поток при добавлении в очередь нового рабочего элемента, пока не достигнет предела ThreadPool.MaxThreads (который до смешного высок, IIRC).

Самый простой способ выяснить, является ли это вашимпроблема заключается в том, чтобы взглянуть на ThreadPool.GetAvailableThreads - если он со временем уменьшается, то, возможно, вам следует написать собственный поток для обработки данных и просто поместить его в потокобезопасную очередь в ProcCntrlSSPortDataReceived.

...