如何同步运行连续任务

本文关键字:运行 连续 任务 同步 何同步 | 更新日期: 2023-09-27 18:20:31

我声明了一个方法,该方法应该异步运行Task,然后,当Task完成时,同步运行指定的委托

C#示例:

private void WaitUntilLoadedAsync(Process p, Action callback, int timeout = 1500)
{
    Task.Factory.StartNew(() => ProcessUtil.WaitUntilLoaded(p, timeout)).
                 ContinueWith(() => callback.Invoke()).RunSynchronously();
}

VB.Net示例:

Private Sub WaitUntilLoadedAsync(ByVal p As Process,
                                 ByVal callback As Action,
                                 Optional ByVal timeout As Integer = 1500)
    Task.Factory.StartNew(Sub() ProcessUtil.WaitUntilLoaded(p, timeout)).
                 ContinueWith(Sub() callback.Invoke()).RunSynchronously()
End Sub

但是,RunSynchronously方法抛出一个System.InvalidOperationException异常,告诉我不能同步运行连续的Task

那么,我该怎么做呢?。

注:

  • 我能够支持Async/Await解决方案。

  • 我将保留我的方法的"微小"逻辑或循环复杂性,我的意思是,它只是一个我在其上传递Acton的方法,没有在该方法或其他可能导致最终用户编写超过Action的复杂事物之外声明委托。该方法本身应该自动执行所有所需的操作,以同步地执行延续任务,而不需要外部的复杂性。

如何同步运行连续任务

因此,正如我从问题和评论中了解到的,您希望在线程池线程(后台线程)上运行任务1,并且希望在UI线程上运行任务2(它是任务1的延续)。

以下是您的操作方法:

private void WaitUntilLoadedAsync(Process p, Action callback, int timeout = 1500)
{
    var thread_scheduler = TaskScheduler.FromCurrentSynchronizationContext();
    Task.Factory.StartNew(() => ProcessUtil.WaitUntilLoaded(p, timeout)).
        ContinueWith(t => callback.Invoke(), CancellationToken.None, TaskContinuationOptions.None,
            thread_scheduler);
}

这段代码所做的是,它要求TPL在一个调度程序上运行延续任务,该调度程序将在UI线程中执行任务。

这假设WaitUntilLoadedAsync是从UI线程调用的。如果不是这样,只需将thread_schedular作为实例变量(或在该方法可访问的某个范围内),并确保从UI线程初始化它。

请注意,控件将立即返回给WaitUntilLoadedAsync的调用方,并且回调将在任务1完成后在UI线程上执行。

如果只想在从UI线程调用WaitUntilLoadedAsync的情况下在UI线程上执行延续任务(否则在线程池线程上执行),则将thread_scheduler定义如下:

var thread_scheduler = SynchronizationContext.Current == null
    ? TaskScheduler.Default
    : TaskScheduler.FromCurrentSynchronizationContext();

听起来你在寻找TaskContinuationsOptions.ExecuteSynchronously

根据MSDN:

指定应同步执行延续任务。指定此选项后,继续在导致先行任务转换到其最终状态的同一线程上运行。如果在创建延续时先行件已经完成,则延续将在创建延续的线程上运行。如果先行件的CancellationTokenSource被释放在finally块中(在Visual Basic中为finally),则带有此选项的延续将在该finally块上运行。只有非常短的持续运行才应该同步执行。

因为任务是同步执行的,所以不需要调用task等方法。等待以确保调用线程等待任务完成。

要使用它,只需使用过载.ContinueWith(Action<task>, TaskContinuationOptions) 将其作为标志传递即可

然而,如果执行父线程的线程被中止(这是不常见的),这将不是同步的。