2011-10-11 98 views
2

我需要取消使用ThreadPool.QueueUserWorkItem(...)開始的後臺任務。我知道一個BackgroundWorker特別爲這類事情構建,但我相信在這種情況下它是過度的,因爲不涉及用戶界面。通過取消,我只是指強制完成回調方法。取消ThreadPool.QueueUserWorkItem任務

在我的課堂上添加類似以下內容的缺陷是什麼?

// Cancellation Property. 
private bool _canceled; 
public bool CancelTask 
{ 
    get { return _canceled; } 
    set { _canceled = value; } 
} 

public void DoSomeTask() 
{ 
    int iterations = 50; 
    ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPoolCallback), iterations); 
} 

private void ThreadPoolCallback(object state) 
{ 
    if (_canceled) 
     return; // don't even start. 

    int iterations = (int)state; 
    for (int i = 0; !_canceled && i < iterations; i++) 
    { 
     // 
     // do work ... 
     // 

     // This allows you to cancel in the middle of an iteration... 
     if (_canceled) 
      break; 
    } 
} 

有沒有更好的方法?

+0

我已經多次使用類似的技術,沒有任何問題;我看到的唯一問題是如果多個線程可能會嘗試寫入'_canceled'。但對於一個簡單的「一次寫入,一次讀取,退出」一種標誌,我從來沒有遇到過問題。雖然我很好奇聽到其他想法。 – CodingGorilla

+1

只要確保_canceled被正確同步。我建議使用互鎖函數來修改該變量,以便存在內存障礙。 –

+2

您必須使用* volatile *作爲_canceled成員聲明*或*使用CancelTask​​屬性獲取器。如果沒有這個,你的工作者方法永遠不會看到更新的確有可能。 BGW的開銷很少,而且代碼已經被數千人測試並由其他人維護。 –

回答

3

我會使用CancelTask​​()方法而不是屬性。關鍵是呼叫者應該能夠取消任務,但是沒有人應該能夠取消任務。

然後,您需要確保_cancelled的讀取和寫入具有適當的內存屏障,否則一個線程可能無法觀察到另一個線程所做的更改。爲此,我會使用Thread.VolatileWrite(在CancelTask​​中)和Thread.VolatileRead(在你的循環中)