18

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

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

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

我想在ContinuationTask中指定它应该在与其前件相同的线程中运行

我在网上搜索过,但我只发现线程在 SynchronizationContext 中运行的要求,因此我开始认为我缺少一些基本规则,特别是关于 Thread.Principal 应该如何工作。

4

4 回答 4

16

首先,请勿TaskContinuationOptions.ExecuteSynchronously用于此目的!您不能在同一线程上强制继续。它只适用于非常高的概率。总有它不起作用的情况:递归过多会导致 TPL 不能同步执行。CustomTaskScheduler也没有义务支持这一点。

这是一个常见的误解,尤其是因为它在网络上被错误地传播。以下是关于该主题的一些阅读: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 不关心我们在回调中做了什么。我们可以做任何我们想做的事情,包括调用多个方法和传递结果。

于 2012-12-27T16:47:39.757 回答
5

来自我的 C# 教科书(C# 4.0 in a Nutshell):

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

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

这是MSDN 文章的链接,其中还包含一些更具体的示例

于 2012-12-27T16:27:34.250 回答
3

设置池线程的标识不是一个好主意。如果您忘记在异常处理程序中清除身份,它将您与此特定线程联系起来,并且有可能在发生异常时“泄露”身份。您最终可能会使用“泄露”的身份运行不相关的任务。

尝试将 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语句确保即使发生异常也会清除模拟身份。

于 2012-12-28T08:24:05.327 回答
3

使用 TaskScheduler.FromCurrentSynchronizationContext() 调用延续:

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

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

于 2013-07-24T04:41:53.750 回答