2012-08-01 80 views
4

劇情簡介:我在做什麼線程錯誤?

我試圖將非線程應用程序轉換爲線程應用程序。我在大約10年的時間裏沒有在應用程序中使用線程,並且對這個概念非常生疏。這只是我沒有抓住的東西。你能看看我的(很短的)代碼之前和之後,看看我做錯了什麼,爲什麼它是錯的?所有幫助非常感謝!謝謝!

錯誤看出:

我的代碼沒有響應。我可以運行並執行這些按鈕來啓動應用程序,但不會啓動一個新線程而只是工作,它們會凍結並顯示「無響應」消息。我不確定我做錯了什麼。我是否錯誤地實現了線程?

非線程代碼:

//this opens the user input windows form 
private void UserInputButton_Click(object sender, EventArgs e) 
{ 
    enumerationStation EnumerationForm = new enumerationStation(); 
    EnumerationForm.Show(); 
    //userform UserForm = new userform(); 
    //UserForm.Show(); 
} 

//this opens the correlationApplication windows form 
private void CorrelationApplication_Click(object sender, EventArgs e) 
{ 
    CorrelationApplication CorrelationApplicationForm = new CorrelationApplication(); 
    CorrelationApplicationForm.Show(); 
} 

破碎線程代碼:

//this opens the user input windows form 
private void UserInputButton_Click(object sender, EventArgs e) 
{ 
    BackgroundWorker bg = new BackgroundWorker(); 
    bg.DoWork += new DoWorkEventHandler(enumerationStuff); 
    bg.RunWorkerAsync(); 

} 
//run enumeration application in new thread 
private void enumerationStuff(object sender, DoWorkEventArgs e) 
{ 
    enumerationStation EnumerationForm = new enumerationStation(); 
    EnumerationForm.Show(); 
} 

//this opens the correlationApplication windows form 
private void CorrelationApplication_Click(object sender, EventArgs e) 
{ 
    BackgroundWorker bg = new BackgroundWorker(); 
    bg.DoWork += new DoWorkEventHandler(correlationStuff); 
    bg.RunWorkerAsync(); 
} 
//run correlation application in new thread 
private void correlationStuff(object sender, DoWorkEventArgs e) 
{ 
    CorrelationApplication CorrelationApplicationForm = new CorrelationApplication(); 
    CorrelationApplicationForm.Show(); 
} 
+3

簡單的回答:不要這樣做。使用線程進行昂貴的計算。使用TPL。 – SLaks 2012-08-01 13:10:40

+3

我敢肯定,從UI線程中打開新的UI形式是一個壞主意。 – asawyer 2012-08-01 13:12:38

+0

另外,好像你是從backgroundworker調用UI方法:'EnumerationForm.Show();'。這應該會爲您彈出一個例外。您應該只在主線程上使用UI方法,並使用其他線程來完成與其他線程無關的其他任務。 – devundef 2012-08-01 13:13:52

回答

4

BackgroundWorkers是專爲正是這樣做的 - 在後臺運行。它們不是爲了顯示新窗口或自己展示任何UI而設計的 - 根據定義,它是前臺工作。 BackgroundWorkers不處理任何消息,因此它們不會響應鼠標點擊,鍵盤輸入或任何事情,這就是爲什麼窗口只顯示「不響應」的原因。

很難回答這個問題,因爲我並不十分清楚你在這裏實際實現的目標。你的第一個非線程代碼有什麼問題?

如果「單個應用程序」(實際上只是表單)凍結整個應用程序,它們可能在UI線程中做了很多工作。在這種情況下,BackgroundWorkers可能是一個解決方案,但是你在錯誤的地方使用它們。找到正在做「很多工作」的代碼(無論是哪種工作),並查看是否可以將該代碼(僅限該代碼)放入BackgroundWorker中。然而,你不能做的是在BackgroundWorker內部對UI做任何事情 - 你只有一個UI線程(你開始的那個線程),只有那個線程可以觸及UI。

+0

我沒有意識到這一點。我已經閱讀了幾個小時的後臺工作人員文檔,並且從未發生過我:)這可能是我的問題 – toosweetnitemare 2012-08-01 13:25:47

2

.NET/Windows用戶界面不允許從任何用戶界面線程執行任何 UI操作。簡而言之,UI本身是單線程的,而任何不接觸UI的長時間運行的操作可以愉快地發生在輔助/後臺線程中。

這就是爲什麼像Control.Invoke這樣的東西存在,以便您可以請求在UI線程上下文中執行一段特定的代碼。

+0

如何使control.invoke適用於這種情況?這聽起來像我想要做的。 – toosweetnitemare 2012-08-01 13:24:45

+1

@toosweetnitemare這就是你想要做的,但這不是你應該做的。你可以使用'Control.Invoke'從後臺線程更新* UI,而不是用它來接受輸入等等。這種事情必須在UI線程上完成。 – James 2012-08-01 13:30:03

+1

@toosweetnitemare:儘管pete說的是正確的,但仍堅持Chris在他上面的評論中指出的方法。除此之外:BackgroundWorker有一個ReportProgress事件,它允許您用工作線程中的信息更新UI,而不會崩潰任何東西。但是,這仍然只有克里斯或詹姆斯指出的情景纔有意義。 – 2012-08-01 13:36:40

2

這裏的主要問題是您試圖在後臺線程上創建&運行GUI組件。鑑於你需要提示用戶輸入,我不明白你爲什麼想要將這些代碼編入單獨的線程。

保持您的表單在UI線程中啓動,然後將這些表單執行的任何額外工作傳遞到後臺線程中。