2012-08-02 45 views
2

假設我有兩個線程。在一個線程中,我正在執行一系列的工作。在另一個線程上,我等待用戶輸入來控制這些作業(即跳到下一個作業)。例如(僞C#):用於處理從另一個線程觸發事件的模式

public class Worker { 

    public List<Job> Jobs { get; set; } 

    public Worker(Controller anotherThread) { 
     anotherThread.SkipJobRequested += OnSkipJobRequested; 
    } 

    public DoWork() { 
     foreach (Job job in Jobs) { 
      // Do various work... 
     } 
    } 

    // Event that fires on Controller thread 
    public void OnSkipJobRequsted(Object sender, EventArgs args) { 
     // Somehow skip to the next job 
    } 
} 

我不確定我應該如何處理跳到下一份工作。發生在我身上的一種可能性是在請求跳過時設置一個實例變量(例如,IsSkipRequested),並在DoWork()內的各個關鍵點檢查它。

是否存在其他可用於處理此事件的模式?

+0

最好的方法可能取決於工作實際在做什麼。它可以在任何時候終止?每項工作一旦開始就完成了嗎?如果正在進行,是否需要取消優雅作業?等你能提供更多的細節? – 2012-08-03 00:14:04

+0

@RJLohan,一份工作一旦開始就不需要完成 - 它可以在任何時候沒有恩典就終止(儘管恩典可能很好,但沒有必要)。 – Eric 2012-08-03 00:22:31

回答

1

如果您製作了List<Jobs> a Queue<Jobs>,而不是執行foreach維護目標中的當前執行作業,您可以簡單地在準備處理時將每個項目出列。

任務並行庫允許您指定一個取消標記(儘管您可能必須將此標記傳遞給您的作業執行代碼,並在那裏處理取消操作),您可以在按下跳過時調用RequestCancellation,然後啓動隊列中的下一份工作。此外,在啓動新任務時,您可以指定要在完成時執行的操作,這可以讓您將任務鏈接在一起,並在需要時跳過任務。下面是一個例子沒有取消標記:

 _currentJob = Jobs.DeQueue(); 
     Task.Factory.StartNew(() => {_currentJob.execute();}, 
     () => 
     { 
      //On task completion logic 
      ExecuteNextJobFromQueue();        
     } 

注意,如果工作正在執行多個任務,而不是一個大阻塞的任務,因爲你需要在作業執行期間檢查取消這種做法可能會工作得最好。

3

另一種模式是.Net類BackgroundWorker,它似乎應該適合您的目的。您可以將作業作爲BackgroundWorker的子類,並循環。不同的是,BackgroundWorker不知道你的UI線程,只知道是否已經請求取消。

在這種模式UI線程會叫CancelAsync,那麼你的DoWork方法將檢查CancellationPending在方便的時間間隔,以決定是否要繼續。您將爲RunWorkerCompleted事件處理程序中的下一個作業調用RunWorkerAsync

+0

有趣的建議,謝謝。除了擁有「IsSkipRequested」標誌之外,它還有什麼好處嗎?這聽起來很相似,但也許它是一種標準可識別模式的優點。 – Eric 2012-08-03 00:25:10

+0

與創建'Task'(.NET 4 TPL)並使用'CancellationToken'類似,是否正確? – Eric 2012-08-03 00:26:43

+1

@Eric它也有一個* IsBusy *屬性和一個* ReportProgress *方法可能有用。至於*任務*,我還沒有用過,但它看起來非常棒。如果你使用.Net 4.5,這可能是使用* await *關鍵字和所有新語法的好機會。 – McGarnagle 2012-08-03 00:35:03

相關問題