2015-10-26 66 views
0

我有這些控制按鈕(Windows.Forms的):如何終止/退出/中止舊線程工作並重新啓動程序?

Start/Restart | Pause | Continue

一旦Start被按下,創建threadPool[workerThreadsCount]ManualResetEvent mre設置爲mre.Set()和線程開始做他們的工作。在一些僞代碼中:

threadStartingPoint() { 
int index = 0; 
while(index !== someMaxCondition) 
     ... // grab some data to work on 
     lock(_lock) { // lock index, so one access at a time 
     index += index; 
     } 
     ... // do some stuff 
     _mre.WaitOne(); // Pause if button Pause is pressed. 
    } 
} 

工作線程像上面的例子一樣工作在循環中。現在如果我按pause,一切停止在_mre.Wait();位置。用continue我可以使用mre.Set()打開大門,一切正常。現在的問題是當我Pause,我想用戶在ContinueRestart之間選擇。 Restart的問題是我不知道如何告訴我的線程退出while loop。因爲如果我只是設置mre.Set()並創建新線程,一段時間以前,舊線程仍然可以使用舊數據循環。

有什麼建議嗎?

+0

您需要使用具有超時值的'WaitOne'的重載。然後在while測試條件下,測試一些暫停或退出條件。 – GreatAndPowerfulOz

+0

fyi'index'是線程本地的,你不需要鎖定它,因爲只有一個線程可以觸摸它。 –

回答

0

「按書」答案是考慮實施CancellationTokenSource

但是,如果您已經有工作代碼,我只需添加一個變量bool restartRequested=false;

當用戶請求重新啓動時,請設置restartRequested=true;並重置_mre。然後打破while循環,並讓線程方法完成,如果restartRequested==true

+0

由於訪問數據時的波動性,多線程中不建議使用簡單變量。 http://www.yoda.arachsys.com/csharp/threads/printable.shtml – Don

+0

@DonJayamanne,通常我會同意你的看法。但是,這段代碼已經在WaitHandle上停止了。這裏波動不是問題。 – bigtlb

2

傳入CancellationToken並讓它檢查每個循環。

private volatile CancellationTokenSource _tokenSource = new CancellationTokenSource(); 

threadStartingPoint() { 
int index = 0; 
var token = _tokenSource.Token; 
while(index !== someMaxCondition && !token.IsCancellationRequested) 
     ... // grab some data to work on 
     lock(_lock) { // lock index, so one access at a time 
     index += index; 
     } 
     ... // do some stuff 
     _mre.WaitOne(); // Pause if button Pause is pressed. 
    } 
} 

當用戶點擊取消按鈕具有其發送一個取消到CancellationTokenSource令牌衍生自。然後,新工作人員可以使用不受先前取消影響的新令牌來源。

private void ButtonCancelClick(object sender, EventArgs e) 
{ 
    //Get a local copy of the source and replace the global copy 
    var tokenSource = _tokenSource; 
    _tokenSource = new CancellationTokenSource(); 

    //Cancel all loops that used the old token source 
    tokenSource.Cancel(); 
    mre.Set(); 
} 
0

您可以創建另一個ManualResetEvent,只有在單擊「重新啓動」按鈕時纔會設置它。 以下是使用新的WaitHandle更新的代碼。

threadStartingPoint() { 
int index = 0; 
//We have two waithandles that we need to wait on 
var waitHandles = new WaitHandle[] {_mre, _restartMre}; 
while(index !== someMaxCondition) 
     ... // grab some data to work on 
     lock(_lock) { // lock index, so one access at a time 
     index += index; 
     } 
     ... // do some stuff 

     //Wait on any one of the wait handles to signal 
     WaitHandle.WaitAny(waitHandles); 
     if (_restartMre.WaitOne(0)){ 
      break; 
     } 
    } 
} 
相關問題