与前一个线程中的延续任务

本文关键字:线程 延续 任务 一个 | 更新日期: 2023-09-27 17:49:55

我有一个WebService来创建一个任务和一个延续任务。

在第一个任务中,我们设置了Thread。CurrentPrincipal

因此,当ContinuationTask启动时,它不再具有Thread.CurrentPrincipal.

我想在ContinuationTask中指定它应该与其前一个在同一线程中运行。

我已经搜索了网络,但我只发现线程在SynchronizationContext中运行的要求,因此我开始认为我错过了一些基本规则,特别是关于如何线程。校长应该工作

与前一个线程中的延续任务

首先,不要将TaskContinuationOptions.ExecuteSynchronously用于此目的!不能在同一线程上强制执行延续。它只有在非常高的概率下才有效。总会有这样的情况:太多的递归会导致TPL不能同步执行。自定义TaskScheduler也没有义务支持这个。

这是一个常见的误解,特别是因为它在网络上被错误地传播。下面是一些关于这个话题的阅读:http://blogs.msdn.com/b/pfxteam/archive/2012/02/07/10265067.aspx

如果你需要在同一个线程上运行,这样做:

Task.Factory.StartNew(() => { First(); Second(); });

如此简单。

让我通过展示另一种解决方案来说明为什么这样做是有效的:

void MyCompositeTask()
{
  var result = First();
  Second(result);
}
Task.Factory.StartNew(() => MyCompositeTask());

这看起来更直观:我们将MyCompositeTask传递给TPL运行。TPL并不关心我们在回调中做什么。我们可以做任何我们想做的事情,包括调用多个方法和传递结果。

从我的c#课本(c# 4.0 in a Nutshell):

你可以通过在调用ContinueWith时指定TaskContinuationOptions.ExecuteSynchronously来强制它们[延续任务]在[作为它们的前一个]线程上执行:这可以通过减少间接来提高非常细粒度的延续的性能。

原则上我还没有尝试过,但它似乎是你正在寻找的,可以与Thread.CurrentPrincipal结合使用。

这里是一篇MSDN文章的链接,还有一些更具体的例子

调用TaskScheduler.FromCurrentSynchronizationContext():

Task UITask= task.ContinueWith(() =>
{
 this.TextBlock1.Text = "Complete"; 
}, TaskScheduler.FromCurrentSynchronizationContext());

复制自https://stackoverflow.com/a/4331287/503969

设置池线程的标识不是一个好主意。它将您绑定到这个特定的线程,并且如果您忘记在异常处理程序中清除标识,则有可能在发生异常时"泄漏"标识。您可能会以使用"泄漏"身份运行不相关的任务而告终。

尝试将WindowsIdentity对象传递给任务并使用WindowsIdentity. impersonate进行模拟。这将允许您使用任何可用的线程,并且即使发生异常也可以安全地清除标识。

你可以尝试这样做:

WindowsPrincipal myPrincipal=...;
...
var identity=(WindowsIdentity)myPrincipal.Identity;
var task=Task.Factory.StartNew(ident=>{
        var id=(WindowsIdentity)ident;
        using(var context=id.Impersonate())
        {
            //Work using the impersonated identity here
        }
        return id;
    },identity).
.ContinueWith(r=>{
        var id = r.Result;
        using(var context=id.Impersonate())
        {
            //Work using the impersonated identity here
        }
});

using语句确保即使发生异常也清除模拟的标识。