Konrad
Konrad

Reputation: 7198

Am I doing it right? Background work in Windows forms application

I have a windows forms application. I want to do something in background after pressing some button.

//---------- MyWorker::Run
public Task Run()
{
   WorkerTask = Task.Factory.StartNew(() =>
   {
       //Access MyWorker's properties etc. causes complications as it runs from 
       // a different thread and I need to use InvokeRequired etc. but not everything has Invoke method implemented.
   }, TokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

   return WorkerTask;
}

//---------- Form event
async void DoSomething(object sender, EventArgs e)
{
   var task = MyWorker.Run();

   await task;
}

However there are some complications when I try to access MyWorker's objects in the run method as it runs in a different thread. What pattern would be prefered here? I was thinking about something like:

//---------- Form event
async void DoSomething(object sender, EventArgs e)
{

   Task.Factory.StartNew(() =>
   {
       var MyWorker1 = new MyWorker(...);
       // Worker is synchronous here
       MyWorker1.Run();
   }, TokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}

But I wouldn't be able to access MyWorker from other methods. Thanks in advance .. I'm confused.

Upvotes: 0

Views: 92

Answers (2)

Stephen Cleary
Stephen Cleary

Reputation: 456322

You shouldn't implement a method entirely in terms of Task.Run (or StartNew); instead, call the method with Task.Run:

async void DoSomething(object sender, EventArgs e)
{
  var task = Task.Run(() => MyWorker.Run());
  await task;
}

This way you can access MyWorker from multiple methods... and multiple threads, of course. It's up to you to apply appropriate synchronization then.

On a side note, you shouldn't ever need to use Invoke or BeginInvoke in modern apps; there are always superior solutions. For example, await will return to the UI thread context automatically. Similarly, Progress<T> can synchronize to the UI context automatically.

Upvotes: 3

Pedram
Pedram

Reputation: 828

You can customize this approach:

var myTasks = new ConcurrentBag<Task>();
var myResults = new ConcurrentBag<int>();

and use it like:

myTasks.Add(Task.Factory.StartNew(() =>
{
    //do something
    myResults.Add(5);
});

Upvotes: -2

Related Questions