locked
Starting task from UI thread RRS feed

  • Question

  • I need start async method F() so that all code between "await <other async method>" in the implementation of F() will be NOT (is synchronized by default) synchronized with UI thread.

    Is my code correct?

    void OnButtonStartClick(..)

    {

      var backup = SynchronizationContext.Current;

      SynchronizationContext.SetSynchronizationContext(null);

      var task = F();

      SynchronizationContext.SetSynchronizationContext(backup);

      await task;

      this.label.Text="Completed!";

    }


    Sergey.
    Tuesday, February 8, 2011 5:33 PM

Answers

  • Hi Sergey-

    When you await a task, the await first tries to capture whatever SynchronizationContext is current.  If it gets one, when the await completes it'll post back to that context.  If it doesn't get one, it grabs whatever TaskScheduler is current (and it'll always get one, as TaskScheduler.Current defaults to TaskScheduler.Default (the thread pool) if there's no task currently running); when the await completes, it'll schedule back to that scheduler.

    This means, then, that if you want to control where your awaits go, you can either implement a SynchronizationContext and set it as current onto the current thread before the await (you'll also need to make sure that it's current on all threads targeted by the sync context), or you can implement a TaskScheduler and schedule your work to it, e.g.

    Task.Factory.StartNew(() =>
    {
        F();
    }, CancellationToken.None, TaskCreationOptions.None, yourTaskScheduler);

    In this example, F() will see TaskScheduler.Current equal to yourTaskScheduler, and unless there's a synchronization context that's current on those threads, all awaits inside of F() will by default automatically get scheduled back to yourTaskScheduler.

    Tuesday, February 15, 2011 3:42 PM
    Moderator
  • Hi Sergey-

    Yes, the execution GG and HH will be serialized.

    Sunday, February 20, 2011 4:29 PM
    Moderator

All replies

  • I need start async method F() so that all code between "await <other async method>" in the implementation of F() will be NOT (is synchronized by default) synchronized with UI thread.

    Is my code correct?

    void OnButtonStartClick(..)

    {

      var backup = SynchronizationContext.Current;

      SynchronizationContext.SetSynchronizationContext(null);

      var task = F();

      SynchronizationContext.SetSynchronizationContext(backup);

      await task;

      this.label.Text="Completed!";

    }


    Sergey.

    One more issue.

    How can specify  thread to "post" code between "awaits" to it?


    Sergey.
    Wednesday, February 9, 2011 4:42 PM
  • Hi Sergey-

    Your solution of nulling out the sync context and then restoring it will work.  You can also use the ConfigureAwait method on an individual await operation to suppress the default marshaling behavior.  An easier solution would just be to run F() where there is no sync context, e.g. on the ThreadPool:

    void OnButtonStartClick(...)
    {
        var task = await TaskEx.Run(() => F());
        await task;
        this.label.Text = "Completed";
    }

    or just:

    void OnButtonStartClick(...)
    {
        await TaskEx.RunEx(() => F());
        this.label.Text = "Completed";
    }

     

    Tuesday, February 15, 2011 5:28 AM
    Moderator
  • Hi Sergey-

    I'm not understanding your question about posting... can you clarify?  Do you mean you want all of your awaits to return to a specific thread of your choosing?

    Tuesday, February 15, 2011 5:29 AM
    Moderator
  • Hi Sergey-

    I'm not understanding your question about posting... can you clarify?  Do you mean you want all of your awaits to return to a specific thread of your choosing?

    Hi Stephen,

    yes, I mean the same.


    Sergey.
    Tuesday, February 15, 2011 7:00 AM
  • Hi Sergey-

    I'm not understanding your question about posting... can you clarify?  Do you mean you want all of your awaits to return to a specific thread of your choosing?

    I try to explain the reason..

     

    I have a code that implements some logic via async methods. Async processesing is based on "source" events to be fired from different threads.

    My goal is to check and optimize performance, but I would like to keep async methods clear without changes and some hardcoding like posting some to threadpool etc.

    But I'm free to change

    1. "source" events (for example: synchronized them, or send to thread pool)

    2. setting in one place processing mode of code between "awaits" (for example: code between awaits should be executed with custom thread, or be send to threadpool)


    Sergey.
    Tuesday, February 15, 2011 7:16 AM
  • Hi Sergey-

    When you await a task, the await first tries to capture whatever SynchronizationContext is current.  If it gets one, when the await completes it'll post back to that context.  If it doesn't get one, it grabs whatever TaskScheduler is current (and it'll always get one, as TaskScheduler.Current defaults to TaskScheduler.Default (the thread pool) if there's no task currently running); when the await completes, it'll schedule back to that scheduler.

    This means, then, that if you want to control where your awaits go, you can either implement a SynchronizationContext and set it as current onto the current thread before the await (you'll also need to make sure that it's current on all threads targeted by the sync context), or you can implement a TaskScheduler and schedule your work to it, e.g.

    Task.Factory.StartNew(() =>
    {
        F();
    }, CancellationToken.None, TaskCreationOptions.None, yourTaskScheduler);

    In this example, F() will see TaskScheduler.Current equal to yourTaskScheduler, and unless there's a synchronization context that's current on those threads, all awaits inside of F() will by default automatically get scheduled back to yourTaskScheduler.

    Tuesday, February 15, 2011 3:42 PM
    Moderator
  • Hi Stephen,

     

    Can I be sure that here:

     await TaskEx.RunEx(() => F());

    GG() and HH() will be executed sequentialy (but probably in different threads)?


     

    async Task F()

    {

      await G();

      GG();

      await H();

      HH();

    }

     

     

     


    Sergey.
    Friday, February 18, 2011 7:56 AM
  • Hi Sergey-

    Yes, the execution GG and HH will be serialized.

    Sunday, February 20, 2011 4:29 PM
    Moderator