2010-07-09 248 views
2

這是情況。我有一個線程,點擊一個按鈕即可開始。然後它工作大約2分鐘(給予或需要相當多),然後完成,更新UI和一路上。這很好。現在我決定在混音中添加一個「取消」按鈕。我的問題是阻止外部線程的最佳方法是什麼?什麼方法最好完全避免?我可以通過什麼資源來獲得更多關於這個話題的知識。停止線程

另一條信息。該程序不是由我編寫的,我只是「繼承」了它,現在正試圖通過小的方式擴展它的功能,使其更加便於用戶使用。

編輯:使用VS2008的工作和.NET 3.5

回答

12

事實上,如果你想安全地取消一些後臺操作,最好的方法是創建私有布爾字段_isCancelled,它將在GUI線程和後臺線程之間共享。如果用戶按下取消,只需將_isCancelled設置爲false。在後臺線程中定期檢查_isCancelled是否轉爲true並返回該方法。

+7

呀,也'_isCancelled'應該是'volatile'。 – 2010-07-09 08:20:33

+0

我真的希望我可以投票給這個答案不止一個。它幫了我很多。謝謝! – Adkins 2010-07-09 09:12:23

+0

是的,你必須使用volatile關鍵字,或鎖定運算符,以確保你總是有_isCancelled字段的正確值,並避免線程併發。 – Mike 2010-07-09 09:41:33

2

你應該有一個標記的地方,工作線程檢查在一段時間一次。當標誌表示線程應該取消時,它應該停止工作並正常退出。

4

在.NET中做這種類型的東西的一種'最好的'方法是使用BackgroundWorker。

BackgroundWorker的將乾淨處理最新進展(你可以有目前只能靠運氣的工作,或者通過很多繁瑣的invoke()調用的),並且還提供了一個乾淨的取消機制。

BackgroundWorker使用一個池線程而不是專用線程,這也是一種比其他方法更好的方法。

從外部停止線程幾乎總是錯誤的方法,儘管開始時通常會覺得它是你想要做的。

如果您使用的是.NET 4.0,還有一個全新的任務和取消機制,但聽起來對BackgroundWorker的研究對您來說是一個很好的第一點。

+0

我們使用的是.NET 3.5,線程是一個自定義創建,伴隨着這個繼承的代碼。取消機制是線程原生還是隻針對後臺工作者? – Adkins 2010-07-09 08:27:04

+0

@Adkins這僅適用於後臺工作者。 – Marek 2010-07-09 08:58:21

+0

我看到BackgroundWorker具有一些很好的內置功能,但遺憾的是這並不是我可以用於此項目的東西。 – Adkins 2010-07-09 09:27:06

5

我經常在類似情況下使用System.ComponentModel.BackgroundWorker。在UI方面,請調用它的CancelAsync()方法;在工作線程端,定期檢查CancellationPending屬性。

6

什麼是從外部阻止 線程的最佳方法?

線程必須合作。你需要一個共享標誌(布爾)並且線程代碼必須定期檢查它。

什麼方法最好避免 完全?

Thread.Abort()。

2

與其在UI和worker類之間使用共享布爾變量,更清晰的方法是使用重置事件(AutoResetEvents/ManualResetEvent)。

但是它仍然取決於你的線程在做什麼樣的處理。 如果說例如處理文件的循環,則可以使用重置事件線程構造。如果是單一操作(例如複製大文件),那麼您無法取消該操作,而且您也不知道線程當前正在執行什麼操作。

它還將幫助,如果你知道用戶想要通過點擊取消什麼 - 丟棄線程正在做的一切,或採取應用到以前的狀態或完成當前正在處理的項目,並立即返回。