2017-07-21 24 views
1

我正在嘗試爲我的視圖模型創建一個幫助器方法,該方法需要執行一組操作並阻止其他同時發生的操作的集合。Chain ContinueWith在運行時的任務

我相信這是一個主要的候選人使用Task.ContinueWith和我的原始硬編碼功能工作沒有問題使用此方法,但是當我試圖在運行時構建操作我遇到問題,我的任務運行在不同的訂單超出我的預期。

我班的樣子:

internal abstract class ViewModel : IViewModel 
{ 
    private readonly AutoResetEvent autoResetEvent = new AutoResetEvent(true); 

    protected Task SynchronousTask(IList<Action> actions) 
    { 
     var initialTask = new Task(() => this.autoResetEvent.WaitOne()); 

     for (var i = 0; i < actions.Count; i++) 
     { 
      var i1 = i; 
      initialTask.ContinueWith(task => actions[i1]()); 
     } 

     initialTask.ContinueWith(task => this.autoResetEvent.Set()); 

     initialTask.Start(); 
     return initialTask; 
    } 
} 

基本上我想等上AutoResetEvent阻止運行,直到這個已設置的新任務。然後,我循環執行每個任務,將它們添加爲初始任務的延續,最後以延續結束設置AutoResetEvent

從理論上講,這看起來應該可以工作,但是當我運行它時,最終會以不正確的順序運行延續。

據我所知,還有其他方法可以在不使用ContinueWith的情況下做到這一點,但我想看看我在哪裏以及如何使用此方法出錯。

+2

如果您只是在循環內部使用'await Task.Run(action)',就可以擺脫所有代碼。當執行命中第一個「await」時,調用者將返回一個Task。無需事件或冷的任務。 –

+0

@PanagiotisKanavos是的我同意這會更好,並希望這是人們將來做的事情,但我主要關心的是我出錯的地方,現在我認爲這是一個愚蠢的疏忽。 –

回答

5

當你添加多個延續到同一個任務,如你的例子 - 他們是開始以某種順序(據我所知,該順序沒有記錄,你不應該依賴它 - 但它似乎它們以先進先出的順序啓動),但它們不以運行特別是順序。他們開始後 - 他們都平行運行。因此,在您的情況下,所有操作和autoResetEvent.Set()將在initialTask完成後幾乎同時執行。如果您需要順序執行 - 只需將所有代碼放入一個Task並運行它,則無需在此處使用ContinueWith。如果您確實想要使用ContinueWith - 連鎖延續(請撥ContinueWith上一次ContinueWith的結果)。

+0

現在我明白我要去哪裏錯了我沒有考慮過我將所有'ContinueWith's添加到相同的'Task',而不是將它們'鏈接'到之前的'ContinueWith'' Task'。 –

2

所有你需要的只是鏈接到最後的任務,而不是最初的任務。 想象一下,將下一個任務掛鉤到前一個任務,而不是將所有任務掛接到第一個任務。

public static Task SynchronousTask(List<Action> actions) 
{ 
    var initialTask = new Task(() => autoResetEvent.WaitOne()); 

    Task lastTask = initialTask; 
    for (int i = 0; i < actions.Count; i++) 
    { 
     int i1 = i; 
     lastTask = lastTask.ContinueWith(task => actions[i1]()); // here 
    } 

    lastTask.ContinueWith(task => autoResetEvent.Set()); 

    initialTask.Start(); 
    return initialTask; 
}