繁体   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