Continuation Task in the same thread as previous

前端 未结 4 515
梦如初夏
梦如初夏 2020-12-16 13:42

I have an WebService that creates a task and a continuation task.

In the first task we set Thread.CurrentPrincipal

Hence, When the Continuat

相关标签:
4条回答
  • 2020-12-16 14:13

    Call the continuation with TaskScheduler.FromCurrentSynchronizationContext():

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

    Copied from https://stackoverflow.com/a/4331287/503969

    0 讨论(0)
  • 2020-12-16 14:16

    From my C# textbook (C# 4.0 in a Nutshell):

    You can force them [continuation tasks] to execute on the same thread [as their antecedent] by specifying TaskContinuationOptions.ExecuteSynchronously when calling ContinueWith: this can improve performance in very fine-grained continuations with lessening indirection.

    In principal I haven't tried this but it seems to be what you're looking for and could be used in conjunction with Thread.CurrentPrincipal.

    Here is a link to an MSDN article with some more concrete examples as well

    0 讨论(0)
  • 2020-12-16 14:21

    First of all, don't use TaskContinuationOptions.ExecuteSynchronously for this purpose! You can't force the continuation on the same thread. It only works with very high probability. There are always cases where it does not work: Too much recursion will cause the TPL not to execute synchronously. Custom TaskSchedulers are also not obliged to support this.

    This is a common misconception, especially because it is being wrongly propagated on the web. Here is some reading on that topic: http://blogs.msdn.com/b/pfxteam/archive/2012/02/07/10265067.aspx

    If you need to run on the same thread, do this:

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

    So easy.

    Let me illustrate why that works by showing an alternative solution:

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

    This looks more intuitive: We pass MyCompositeTask to the TPL to run. The TPL does not care what we do in our callback. We can do whatever we want, including calling multiple methods and passing the results.

    0 讨论(0)
  • 2020-12-16 14:21

    Setting a pool thread's identity is not a good idea. It ties you to this specific thread and and risks "leaking" the identity in case of exceptions, if you forget to clear the identity in an exception handler. You may end up with unrelated tasks running using the "leaked" identity.

    Try passing the WindowsIdentity object to the tasks and impersonate using WindowsIdentity.Impersonate. This will allow you to use any available thread and will safely clear the identity even if an exception occurs.

    You can try something like this:

    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
            }
    });
    

    The using statements ensure that the impersonated identity is cleared even if an exception occurs.

    0 讨论(0)
提交回复
热议问题