2011-01-11 2 views
1

У меня есть многопоточное приложение C# .NET, которое замораживает интерфейс. Что необычно в этом, так это то, что интерфейс не замерзает, если я не позволяю системе простаивать достаточно долго, чтобы заставка запустилась (что требует от меня повторного ввода пароля для повторного доступа к системе). Когда интерфейс снова станет видимым (после того, как я успешно ввел свой пароль), интерфейс заблокирован. Пока я не позволяю запускать скринсейвер, интерфейс не блокируется.Интерфейс зависает в многопоточном приложении C#

Следует отметить, что у меня есть два разных исполняемых файла, которые обращаются к одной и той же DLL, и эта проблема возникает независимо от того, какое приложение я использую для доступа к DLL. Это, по-видимому, означает, что проблема связана с DLL, поскольку два приложения полностью различаются (C++/MFC) и (C# /. NET), кроме того, как они относятся к DLL.

Оба exes выполняют аналогичные шаги в том, как они взаимодействуют с DLL. Они выполняют вызовы в dll для настройки связи по последовательному порту, открывают окно состояния в DLL, запускают поток в DLL для мониторинга коммуникационного порта и затем запускают поток в основном приложении, которое контролирует стек в DLL.

Когда данные получены из коммуникационного порта потоком в DLL, он анализируется и его результаты помещаются в стек, а затем отправляются в окно состояния через делегат. Когда поток в exe видит данные в стеке, он выводит данные в главное окно, также используя делегат.

Я обнаружил, что если я добавлю код в поток внутри DLL, чтобы он вызывал Application.DoEvents() каждые 30 секунд, интерфейс будет заморожен на 30 секунд, а затем возобновит активность, как обычно. Я полагаю, что что-то блокирует основной поток и заставляет DoEvents() срабатывать, как будто разбивает блокировку, но я понятия не имею, что может вызвать эту блокировку.

Эта проблема возникает как на моей машине разработки, так и на тестовой машине.

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

Я много лет проделывал многопрофильное программирование и никогда не видел ничего подобного; поэтому любой совет будет очень признателен.

Спасибо.

+3

Приостановите замороженный пользовательский интерфейс в отладчике и посмотрите на стек вызовов. – SLaks

+0

Вы пытались вызывать методы DLL только из потоков, отличных от UI, и сортировать их по потоку пользовательского интерфейса? – RobS

+0

Это может быть не совсем полезно, но есть ли у вас включенное энергосбережение, которое произойдет, когда заставка запустится? (Я думаю, что это может помешать портам спать.) – vlad259

ответ

6

Это проблема, которая обычно вызвана классом SystemEvents, когда у вас есть нестандартный способ инициализации вашего пользовательского интерфейса. Использование потоков, в частности. Запустите свою программу, Debug + Break All, Debug + Windows + Threads. Если вы видите поток с именем «.NET SystemEvents», то вы почти гарантированно получите это.

Некоторые фон: класс SystemEvent поддерживает как консольные приложения, так и графические приложения. Для последнего он должен запускать обработчики событий в потоке пользовательского интерфейса. В первый раз, когда одно из его событий подписано, оно создает небольшое невидимое вспомогательное окно для получения системных уведомлений. Он может сделать это двумя способами, создав окно на вызывающем потоке или запустив вспомогательный поток. Он принимает решение на основе значения Thread.GetApartmentState(). Если это STA, то он может создать окно в вызывающем потоке, и все обратные вызовы событий могут быть правильно привязаны к этому потоку.

Это не так, если созданный вами не создается в потоке пользовательского интерфейса. Например, экран заставки. Это окно может содержать элементы управления, которые заинтересованы в системном событии, таком как UserPreferenceChanged, чтобы они могли правильно перерисовываться. Теперь он использует вспомогательный поток, и любое событие будет запущено из этого вспомогательного потока, а не потока пользовательского интерфейса. Отравить любое окно, которое работает в потоке пользовательского интерфейса.Сеанс отключается от заблокированной рабочей станции (включая экранную заставку) по какой-то загадочной причине, которая может вызвать тупик. Вы также можете увидеть случайную неудачу в живописи, менее неприятный результат использования окон из неправильной нити.

Short от фиксации порядка инициализации, обходной путь, чтобы поставить это в методе Main(), перед тем создаются любые окна:

Microsoft.Win32.SystemEvents.UserPreferenceChanged += delegate { }; 
+0

Я могу добавить это достаточно легко для приложения C# /. NET, которое вызывает эту DLL, но что мне делать для приложения C++/MFC, которое вызывает эту DLL? – PhilGyro

+0

Erm, вызывать функцию инициализации? Правильно ли инициализирует поток C++ код (CoInitializeEx для выбора STA)? Вам лучше проверить Thread.CurrentThread.GetApartmentState() в этой функции init. –

+0

Я проверил состояние квартиры Current Thread при первом входе в DLL и настроен для STA. Я также добавил строку, которую вы рекомендовали выше, к основному методу моего C# exe перед Application.Run(), и это не имело никакого значения. Когда я запускаю exe, я открываю окно основной формы, а затем, когда пользователь нажимает кнопку, вызов выполняется в DLL, чтобы открыть COM-порт и запустить поток. Когда пользователь выбирает режим для выполнения, exe делает другой вызов в DLL, который открывает окно состояния, а затем предупреждает поток в DLL, чтобы начать сбор данных. – PhilGyro

0

Проблема действительно кажется, связано с контролем ActiveX вероятно, неправильно использовалось в форме. Я переключился на использование библиотеки последовательных портов в .NET и не смог воспроизвести мою проблему. Спасибо всем, особенно Хансу за помощь.

0

У меня такая же проблема, как и мой компьютер, просто зависает, когда открывается экранная заставка, или я блокирую свой компьютер, и монитор идет спать. Я на 95% уверен, что в моем многопоточном приложении есть взаимоблокировки. Посмотрите и определите, существуют ли какие-либо взаимоблокировки в вашем коде.

Смежные вопросы