2011-01-13 83 views
0

我有一個C#.NET多線程應用程序凍結了界面。不尋常的是,除非我讓系統閒置足夠長的時間以使屏幕保護程序啓動(這要求我重新輸入密碼以重新訪問系統),否則界面不會凍結。當界面再次可見時(我成功輸入密碼後)所有的窗口都是白色的。我可以看到窗口標題,移動窗口,最小化窗口等,但屏幕不會重新粉刷。當我全部打開並進入調試器時,調用堆棧會有Application.Run(),外部代碼,然後「處於睡眠,等待或加入」狀態。我在我打開的所有四個線程中放置了中斷點,並且它們仍在運行,它只是主應用程序的UI線程被阻止。當我查看我的線程列表時,我的主線程和四個工作線程現在由我的主線程和11個工作線程組成。我沒有打開這麼多的線程,所以它必須是serialport類。c#多線程應用程序中的界面凍結

現在讓我來描述一下我的程序。

我的主應用程序允許用戶從串口收集和監測數據。我通過以下方式實現了這一點。當需要連接時,主應用程序上按下一個按鈕,該應用程序調用一個打開狀態窗口的DLL中的函數,然後啓動一個監視串行端口的線程。當該函數返回時,主應用程序啓動一個線程來監視在初始化DLL時創建的隊列。當從串口收到數據時,數據被解析,然後更新狀態窗口(通過委託),並將數據推送到隊列中。當主應用程序工作線程看到隊列中的數據時,它會檢索它並使用委託在主應用程序的列表框中發佈它。在所有情況下,我都使用BeginInvoke來調用這些代表。

我的DLL包含兩個可以與之通信的不同類型設備的庫。

當我連接到兩個設備時會發生此問題;因此每個設備有四個工作線程兩個線程。 DLL本身被設置爲一個通信對象,所以我可以很容易地從C++/MFC應用程序和C#應用程序訪問它,它們都使用它。

我發現,如果我將代碼添加到DLL中的線程,因此它每30秒調用一次Application.DoEvents(),接口將被凍結約30秒,然後像平常一樣恢復活動。我認爲阻塞主線程並強制DoEvents()啓動似乎破壞了鎖定,但我不知道可能會導致此鎖定。這不是一個解決方案,只是一些有趣的事情。

我將不勝感激您的任何建議。謝謝。

+0

[多線程C#應用程序中的接口凍結]的可能的重複(http://stackoverflow.com/questions/ 4659283/interface-freeze-in-multi-threaded-c-application) –

回答

2

我發現如果我將代碼添加到DLL中的線程中,因此每30秒調用一次Application.DoEvents(),接口將被凍結約30秒,然後恢復正常的活動。我認爲阻塞主線程並強制DoEvents()啓動似乎破壞了鎖定,但我不知道可能會導致此鎖定。這不是一個解決方案,只是一些有趣的事情。

我建議在新的Visual Studio 2010 Concurrency Profiler下運行您的程序。這將在運行時向您顯示哪些線程被阻塞以及它們正在等待哪些對象。線程爭用被明確標記並突出顯示給你。

您可以使用它來輕鬆確定導致您的UI線程死鎖的代碼。

+0

聽起來很有希望。我只有2008年,所以我想是時候升級了。謝謝。 – PhilGyro

1

嘗試將您的線程起始代碼更改爲Thread.Start()而不是BeginInvoke()。BeginInvoke不會讓線程單獨與UI分離,因爲它可能與DoEvents奇怪地交互。您可以閱讀BeginInvoke以及它在這裏的工作方式:http://www.codeproject.com/KB/cs/begininvoke.aspx

另外,DoEvents在應用程序中從不需要,並且可能導致許多意外行爲。使用包裝在Control.Invoke(...)語句中的UI調用進行線程化。如果你使用的是.NET 3.5+,你可以通過這樣的代理來簡化它:Invoke((Action)delegate() {*code goes here*});

+0

我不使用BeginInvoke來啓動我的線程,我使用它來調用委託函數。 – PhilGyro

+0

+1在這裏,我昨天有一個不同的GUI線程問題。從BeginInvoke切換到Thread.Start()是解決方案的一部分。最後一部分涉及啓動過程中線程間時序的微妙之處。 – winwaed