簡體   English   中英

如何排隊/等待TPL任務完成

[英]How to queue/wait for TPL tasks to complete

我需要有關TPL和任務的幫助

這是我的情況:

  1. 我有一些產生任務的事件處理程序。 如果一個事件在其上一個任務完成之前被調用,我想在繼續之前等待(阻止)它。

  2. 我有一個同步方法,該方法在被調用時必須等到任何事件處理程序產生的所有任務完成后再繼續。


public void DoSomething()
{
    // Expects any running tasks from OnEvent1(), OnEvent2(), OnEvent3()
    // to be completed before proceeding.
}

public void OnEvent1()
{
    Task.Factory
    .StartNew(()=>{ /*Long running task*/ })
    .ContinueWith(task=>{ /* Updates UI */ });
}

public void OnEvent2()
{
    Task.Factory
    .StartNew(()=>{ /*Long running task*/ })
    .ContinueWith(task=>{ /* Updates UI */ });
}

public void OnEvent3()
{
    Task.Factory
    .StartNew(()=>{ /*Long running task*/ })
    .ContinueWith(task=>{ /* Updates UI */ });
}

實際情況是:

  • OnFetchData() =>生成任務。 此后的所有后續調用都需要排隊。
  • OnSyncSettings() =>生成任務。 此后的所有后續調用都需要排隊。

  • OnAutoBackup() =>同步方法。 保存之前,請等待其他任務(例如,“獲取數據/同步”設置)完成。

  • OnFullBackup() =>同步方法。 手動運行FetchData()和SyncSettings(),等待完成,然后繼續。

我的問題很簡單:我該怎么做?

這種方法正確嗎?

  1. 每個事件處理程序都會記住其最后一個。 調用時,它將等待列表中的所有任務完成后再繼續。

  2. 對於同步方法,它需要等待所有任務(從每個事件處理程序)執行


Task _lastEvent1Task;
public void OnEvent1()
{
    // Wait for all tasks to complete before proceeding
    if (_lastEvent1Task!=null)
    _lastEvent1Task.Clear();

    // Spawns new task
    _lastEvent1Task = Task.Factory.StartNew(()=>{ });
}

public void OnEvent3()
{
    // Wait for any running tasks to complete before proceeding
    if (_lastEvent1Task != null) _lastEvent1Task.Wait();
    if (_lastEvent2Task != null) _lastEvent2Task.Wait();
    ...
    // Proceed

}

謝謝!


[編輯]

當DoSomething()正在等待並且引發Event1時? 如果DoSomething()正在運行並且引發了事件該怎么辦?

OnEvents()

  • 如果是第一個任務:產生任務並異步執行
  • 如果先前的任務仍在運行,請排隊/阻止。 關鍵部分。
  • 假設:
    • 這些事件通常不會多次引發。
    • 用戶界面應防止用戶在運行時引發同一事件。

DoSomething() (調用時)

  • 假設:事件通知被禁用。
  • 假設:沒有新事件排隊。
  • 預期:等待所有剩余的排隊任務完成后再繼續
  • 預期:將是一個同步調用,並且直到通過執行才返回給調用者

您描述的方法存在並發問題。 例如,在對_lastEvent1Task進行null檢查_lastEvent1Task ,其他線程可能_lastEvent1Task設置為null,從而導致NullReferenceException

我假設每個任務都應該同步運行,但有些不應阻塞。 實現此目標的最佳方法是使用僅利用單個線程的TaskScheduler ,您可以在此處找到示例。

var scheduler = new SingleThreadedTaskScheduler();
var taskFactory = new TaskFactory(scheduler);

對於非阻塞方法,您將得到以下內容:

public void NonBlockingMethod()
{
    taskFactory
        .StartNew(() => { /* Long-running work. */ })
        .ContinueWith(t => { /* Update UI. */ });
}

對於阻塞方法,您將獲得:

public void BlockingMethod()
{
    taskFactory
        .StartNew(() => { /* Do work. */ })
        .Wait();
}

在計划任務時,任務計划程序將僅使用一個線程來計划任務,從而確保所有任務都同步運行。

我認為您需要使用ParExtSamples中的任務計划程序。 通常,您需要為您的OnEventsOrderedTaskScheduler(),然后等待所有預定的任務在DoSomething的完成()方法,或者干脆在同一OrderedTaskScheduler安排您DoSomething的()方法,它只會一次任務執行,預定在此之前,已經完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM