6

I know this question has been asked before, but I didn't get the right answer after googling SO.

I have these lines of code:

Task.Run(() => DoSomething())
    .ContinueWith(t=>Log.Error(t,"Error"), TaskContinuationOptions.OnlyOnFaulted);

Task.Factory.StartNew(() => DoSomething())
    .ContinueWith(t=>Log.Error(t,"Error"),TaskContinuationOptions.OnlyOnFaulted);

After a successful run of DoSomething, Task.Run throws TaskCanceledException while Task.Factory.StartNew works fine. Why?

further reading: Stephen Clearly on why not use Task.Factory.StartNew
MSDN Link

UPDATE 2: Sample Code:

private async void button27_Click(object sender, EventArgs e)
{
    var r = new Random(System.DateTime.Now.Millisecond);

    await Task.Factory.StartNew(
        () => {
            Divide(r.Next(100), r.Next(-1, 10));
            Log.Information("Divide Done!");
        },
        CancellationToken.None,
        TaskCreationOptions.DenyChildAttach,
        TaskScheduler.Default)
    .ContinueWith(
        t => {
            Log.Error(t.Exception,"There is an exception on Divide");
        },
        TaskContinuationOptions.OnlyOnFaulted);
}

private static void Divide(int a, int b)
{
    var c = a/b;
}
Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
Milad
  • 539
  • 8
  • 21
  • Possible duplicate of [Regarding usage of Task.Start() , Task.Run() and Task.Factory.StartNew()](http://stackoverflow.com/questions/29693362/regarding-usage-of-task-start-task-run-and-task-factory-startnew) – smoksnes Nov 15 '16 at 11:28
  • No, it's not. It does not answer my question which is why throwing exception occurs. It describes what I already know. Thanks. – Milad Nov 15 '16 at 11:29
  • 2
    I have rolled back your question, because you completely changed the it, invalidating existing answers. If you have a new question, please post a new question. – svick Nov 15 '16 at 12:38
  • @Sepinood - Ok, I retracted the close-vote. Even though I believe the title _What is the difference between Task.Run and Task.Factory.StartNew?_ is answered in the suggested duplicate. And all the current answers more or less states the same thing as the suggested duplicate and quotes the same source. – smoksnes Nov 15 '16 at 13:36
  • @smoksnes Thanks for your time. I appreciate it. – Milad Nov 16 '16 at 05:31

1 Answers1

6

Task.Run is actually implemented in terms of the same logic used for Task.Factory.StartNew, just passing in some default parameters. When you pass an Action to Task.Run:

Task.Run(someAction);

that’s exactly equivalent to:

Task.Factory.StartNew(someAction, 
    CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

Read more here.

If you pass CancellationToken.None, TaskCreationOptions.DenyChildAttach and TaskScheduler.Default arguments for Task.Factory.StartNew parameters you should see the same result.

CharithJ
  • 46,289
  • 20
  • 116
  • 131
  • 2
    @Sepinood: May be this http://stackoverflow.com/questions/26577519/why-is-taskcanceledexception-thrown-and-does-not-always-breaks-into-the-debugger or http://stackoverflow.com/questions/27196451/when-does-task-runaction-cancellationtoken-throw-taskcanceledexception – CharithJ Nov 15 '16 at 11:38
  • Thanks, it helped me. I updated the question totally. I think it is related to design of TPL. – Milad Nov 15 '16 at 11:56
  • 3
    You won't see the exact same behavior, there is one important diffrence. `Task.Run(` has overloads that take in a `Func` or `Func>` as the paremeter. This allows you to pass in async functions in to `Task.Run(` if you try to do a async function with `StartNew(` you must call `.Unwrap()` on the returned task to get the same behavior. – Scott Chamberlain Nov 18 '16 at 22:39
  • @ScottChamberlain thanks for the brilliant set of details for good clarity – Mrinal Kamboj Nov 24 '16 at 07:38