Is it possible to pass a Task<T> (with return value) to an existing (i.e already running) Thread

133 views Asked by At

In wpf I have two windows in separate threads.
From Window A' in Thread A I would like to start a Task in Tread B of Window B' and await the return value in Thread A.
It suppose it is possible but how?
Do you know an example perhaps?

2

There are 2 answers

1
Stephen Cleary On

Multiple WPF UI threads is a pretty advanced scenario.

You should be able to do it by having Thread B expose a task factory:

 TaskFactory _taskFactory;
 public TaskFactory TaskFactory { get { return _taskFactory; } }

At some point in Thread B's startup do something like this:

 // Startup code running on Thread B
 _taskFactory = new TaskFactory(
     TaskScheduler.FromCurrentSynchronizationContext());

Then you can consume the factory from Thread A, allowing Thread A (or anyone) to queue work to Thread B:

 await _threadB.TaskFactory.StartNew(() =>
 {
   ...
 });
0
Panagiotis Kanavos On

As I understand it, the actual problem is how to initiate an action on Window B from Window A, when both windows run in separate threads.

In this case, you can use SynchronizationContext.Post or SynchronizationContext.Send to start the action on the second window's synchronization context without starting a task. Send will block the calling thread until the callback is processed, while Post will return immediatelly. This makes Post better suited to the scenario.

The end result is the same as creating a Task on Thread B. The callback will execute on the Thread B, but now you avoid the work of creating and dispatching a Task and it requires somewhat less code.

To make this tidy, you can store a reference to the current Synchronization context when you create a new instance of Window B and use it in a wrapper method in Windows B:

public partial class WindowB : Window
{
    private SynchronizationContext _context;

    ...

    protected override void OnActivated(EventArgs e)
    {
        base.OnActivated(e);
        _context = SynchronizationContext.Current;
    }

    public void PostAction(string data)
    {
        _context.Post(ActualAction,data);
    }

    private void ActualAction(object state)
    {
        Title = state.ToString();

    }
}