2013-10-03 48 views
3

我正在開發一個將有一個「索引服務」作爲後臺任務運行的WPF應用程序。索引服務將利用監視文件夾的FileSystemWatcher - 文件更改時,索引服務將讀取文件內容並更新索引(我正在使用Lucene.Net)。我的索引服務是一個單獨的,並會在應用程序啓動這樣開始: -後臺任務 - 如何以受控方式停止?

new TaskFactory().StartNew(_indexingService.StartService); 

StartService()方法看起來是這樣的: -

private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false); 

public void StartService() 
{ 
    var watcher = new FileSystemWatcher 
    { 
     // Set the properties 
    }; 
    watcher.Changed += UpdateIndexes(); 

    _resetEvent.WaitOne(); 
} 

當應用程序被關閉,我打算調用這個方法,我的理解會結束索引服務後臺任務: -

public void StopService() 
{ 
    _resetEvent.Set(); 
} 

首先,這是正確的「模式」啓動和停止應該在應用程序的生命週期中運行的後臺任務?

其次,這種關機有多「優雅」?假設觀察者Changed事件處理程序已經觸發並遍歷文件,讀取它們並更新索引。如果任務已停止,此流程是否會在流程中斷,或者事件處理程序方法是否會首先運行完成?

+1

http://msdn.microsoft.com/en-us/library/dd997364.aspx – Ani

回答

3

您可以使用取消令牌:

CancellationTokenSource CancelationToken = new CancellationTokenSource(); 
    new TaskFactory().StartNew(_indexingService.StartService,CancelationToken, 
           TaskCreationOptions.LongRunning) 
.ContinueWith(TaskCancelationCallBack,TaskContinuationOptions.OnlyOnCanceled); 

您可以使用取消令牌無論您的應用程序:

CancellationTokenSource.Cancel(); 

您可以檢查您的令牌將被取消,並拋出從取消異常任務內部:

if (CancelationToken.IsCancellationRequested) {  

    CancelationToken.Token.ThrowIfCancellationRequested(); 
}   

您可以在ContinueWith回調中獲取任務狀態:

private void TaskCancelationCallBack(System.Threading.Tasks.Task task) 
{ 
    if (task.Status == System.Threading.Tasks.TaskStatus.Canceled) 
    { 
     //Canceled 
    } 
} 

編輯:在這種情況下,我們使用了TaskContinuationOptions.OnlyOnCanceled所以在TaskCancelationCallBack檢查是不必要的。它只會在這個前提下被解僱。

+0

答案几乎是正確的。有幾個錯誤需要修復才能使其工作:w ** StartNew **方法需要CancellationToken,而不是CancellationTokenSource參數。所以,你需要將Token屬性傳遞給方法。此外,它期望您通知您要使用哪個TaskScheduler。您可以傳遞Current或Default。還有一些其他的小修正,但是當你嘗試編譯代碼時你會遇到它們。 –

0

如果您取消了waitOne的呼叫,該任務仍然會結束。

爲了有一個後臺任務實際上做的事情,在某些時候將需要一個循環,處理,這樣

void ProcessItems() 
{ 
    while(workItems.Count > 0) 
    { 
     ProcessItem(workItems[0]); 
    } 
} 

如果你想優雅地擺脫困境,你可以做兩件事情。在我的例子中,我會有一面旗幟。

bool m_IsRunning = true; 
public void Stop() 
{ 
    m_IsRunning = false; 
} 
void ProcessItems() 
{ 
    while(workItems.Count > 0 && m_IsRunning) 
    { 
      ProcessItem(workItems[0]); 
    } 
} 

使用任務並行庫,您還可以傳入一個CancellationToken

在任務類,消除涉及 用戶委託,其代表一個或取消操作和代碼 請求該消除之間的合作。成功取消涉及 調用CancellationTokenSource的請求代碼。取消方法, 和用戶委託及時終止操作。 您可以使用這些選項之一終止操作:

  • 通過簡單地從委託返回。在很多情況下,這是足夠的;但是,以這種方式「取消」的任務實例將轉換爲RanToCompletion狀態,而不是「已取消」狀態。

  • 通過拋出一個OperationCanceledException並將它傳遞給請求取消的標記。使用ThrowIfCancellationRequested方法的首選方法是
    。以這種方式取消的任務轉換到取消狀態,調用代碼可以使用該狀態來驗證任務是否響應其取消請求

http://msdn.microsoft.com/en-us/library/dd997396.aspx