2016-08-01 57 views
0

我有以下代碼塊正在由定時器啓動:正確的使用方法Task.Run和等待

private void CheckForScheduleItemsTimerOnElapsed(Object sender, ElapsedEventArgs elapsedEventArgs) 
{ 
    if (CurrentlyProcessingMsgs) 
     return; 

    CurrentlyProcessingMsgs = true; 

    var task = Task.Run(() => { 
      CheckForScheduleItems.Process(_cancellationToken); 
     }, _cancellationToken); 

    task.Wait(_cancellationToken); 

    CurrentlyProcessingMsgs = false; 
} 

現在我遇到的問題是,在某些情況下,該行

CurrentlyProcessingMsgs = false; 

沒有被調用。這是我的理解,Task.Wait應該等待任務完成,然後繼續,從而重置該標誌。但在某些情況下,這並未發生。 (注意:這個定時器是由一個服務管理的。)發生什麼事情是在關機時,我正在檢查CurrentlyProcessingMsgs的值,有時在任務完成後它仍然是真的。

這樣做的目標是讓多個計時器像上面顯示的一樣被觸發。每個計時器都會執行類似於上面顯示的處理,並且我想在單獨的線程中運行每個進程。我誤解了我對CancellationToken的理解,因此在這種情況下,設置定時器和任務以通過這些方法運行並使每個線程都在單獨線程上的正確方法是什麼?

+0

對於你的定時器的問題,它取決於你正在使用的計時器。一些內置於.NET的計時器會自動使用線程池來啓動計時器(Task.Run也在做同樣的事情)。您需要向我們展示您正在使用的計時器類。你可能已經在做你想做的事。 –

+0

我正在使用System.Timers.Timer類來啓動計時器。 –

+0

是否在其上設置了['Timer.SynchronizingObject'](https://msdn.microsoft.com/en-us/library/system.timers.timer.synchronizingobject(v = vs.110).aspx)值?如果它是'null',你的計時器已經創建了新的線程來運行計時器滴答,你不需要做任何額外的事情。 –

回答

1

如果_cancellationToken被取消,將引發異常。如果你想確保即使被取消或一些其他異常上調ProcessCurrentlyProcessingMsgs = false;在try/finally塊

private void CheckForScheduleItemsTimerOnElapsed(Object sender, ElapsedEventArgs elapsedEventArgs) 
{ 
    if (CurrentlyProcessingMsgs) 
     return; 

    CurrentlyProcessingMsgs = true; 
    try 
    { 
     var task = Task.Run(() => { 
       CheckForScheduleItems.Process(_cancellationToken); 
      }, _cancellationToken); 

     task.Wait(_cancellationToken); 
    } 
    finally 
    { 
     CurrentlyProcessingMsgs = false; 
    } 
} 

P.S.的標誌改變幾乎沒有一個好的理由去做Task.Run然後馬上等待它。只要做下面的應該有非常類似的邏輯就會少得多。

private void CheckForScheduleItemsTimerOnElapsed(Object sender, ElapsedEventArgs elapsedEventArgs) 
{ 
    if (CurrentlyProcessingMsgs) 
     return; 

    CurrentlyProcessingMsgs = true; 
    try 
    { 
     _cancellationToken.ThrowIfCancellationRequested(); 
     CheckForScheduleItems.Process(_cancellationToken); 
    } 
    finally 
    { 
     CurrentlyProcessingMsgs = false; 
    } 
} 

這裏是一個更新的版本與捕捉異常。

private void CheckForScheduleItemsTimerOnElapsed(Object sender, ElapsedEventArgs elapsedEventArgs) 
{ 
    if (CurrentlyProcessingMsgs) 
     return; 

    CurrentlyProcessingMsgs = true; 
    try 
    { 
     _cancellationToken.ThrowIfCancellationRequested(); 
     CheckForScheduleItems.Process(_cancellationToken); 
    } 
    catch (OperationCanceledException ex) 
    { 
     //If the task was canceled for some other reason than our token raise the exception. 
     if(ex.CancellationToken != _cancellationToken) 
      throw; 
    } 
    finally 
    { 
     CurrentlyProcessingMsgs = false; 
    } 
} 
+0

您正在啓動其他線程之一,然後立即阻止當前線程。你沒有額外的併發工作在這裏進行,你所做的只是額外的內存使用額外的調用堆棧。當'Wait'正在'OperationCanceledException'上轉發時,如果你想要正常停止,你需要捕獲異常。 –

+0

我更新了我的問題。我顯然誤解了一些關於如何正確使用TPL的信息。 –

相關問題