在与前一个相同的线程中继续执行任务

我有一个WebService,可以创建任务和继续任务。

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

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

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

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

首先,不要为此目的使用TaskContinuationOptions.ExecuteSynchronously ! 您不能强制在同一个线程上继续。 它只能以非常高的概率运行。 总有一些情况它不起作用:太多的递归会导致TPL不能同步执行。 Custom 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):

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

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

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

设置池线程的标识不是一个好主意。 它将您绑定到此特定线程,如果您忘记在exception处理程序中清除标识,则可能会在exception情况下“泄漏”标识。 您最终可能会使用“泄露”身份运行不相关的任务。

尝试将WindowsIdentity对象传递给任务并使用WindowsIdentity.Impersonate进行模拟。 这将允许您使用任何可用的线程,即使发生exception,也将安全地清除身份。

你可以尝试这样的事情:

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

使用TaskScheduler.FromCurrentSynchronizationContext()调用continuation:

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

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