9

Hi normally I would do this with a Background Worker, but I would like to do it with C# Task instead, just to understand Task better.

The thing is that I have a class with the following properties

    private int _number1;
    public int Number1
    {
        get { return _number1; }
        set { _number1 = value; OnPropertyChanged("Number1");}
    }

    private int _number2;
    public int Number2
    {
        get { return _number2; }
        set { _number2 = value; OnPropertyChanged("Number2");}
    }

Please note that I use the INotifyPropertyChanged.

Number1 = Task<int>.Factory.StartNew(() => GenerateResult()).Result;
Number2 = Task<int>.Factory.StartNew(() => GenerateResult2()).Result;

The GenerateResult and GenerateResult2 are just dumme methods, who sleeps and then return a number.

How would I make this work Async? Since right now, GenerateResult2() is first called when GenerateResult() is finished.

I need it to be able work Async, since I have no idea of when each task is going to finish or even if its going to finish.

gulbaek
  • 2,481
  • 13
  • 44
  • 65

3 Answers3

13

When you get the Result property, you are effectively waiting for the task to complete. It will execute on a background thread but you are waiting in your main thread for the completion before you start the next thread.

See the MSDN doc for details.

You should be able to just assign your properties from the background thread:

Task<int>.Factory.StartNew(() => Number1 = GenerateResult());

WPF databinding will take care of marshalling the PropertyChanged event to the correct dispatcher thread.

Community
  • 1
  • 1
Isak Savo
  • 34,957
  • 11
  • 60
  • 92
  • Thanks alot Isak Savo workes perfect and is simple to read :-) Alot easier then Backgroundworkers – gulbaek Sep 21 '10 at 09:27
  • It is not definite that any Task will execute all the time on a worker thread. Result simply blocks the thread which called it until it is ready to output the data or set an exception. – Theodore Zographos Feb 05 '11 at 11:29
  • Thank you, I had a debug line that was calling .Result so I could do a quick test and it was breaking the async :O – John Jan 31 '12 at 23:34
3

I checked this: Task Parallelism (Task Parallel Library) and it it states that when using System.Threading.Tasks.Task<TResult> the Tasks run asynchronously and may complete in any order. If Result is accessed before the computation completes, the property will block the thread until the value is available.

I think that means if you are accessing .Result before it has a value, as you are doing in your sample code, you will have to wait for it to complete first.

It does make sense as the Result property would not be populated until the Task is completed.

Nope
  • 22,147
  • 7
  • 47
  • 72
  • 2
    Didn't see Isak Savo's answer which already points out that accessing Result will wait for task to complete. – Nope Sep 21 '10 at 08:46
-3
Task<int>.Factory.StartNew(() => GenerateResult2()).ContinueWith(() => GenerateResult());
gandjustas
  • 1,925
  • 14
  • 12
  • 5
    Unless I'm mistaken, this is exactly the same semantics as the OP's code - the second task isn't started until the first has completed. – Isak Savo Sep 21 '10 at 08:38