Reputation: 181
I have a problem in the following code:
static void Main (string[] args)
{
Task newTask = Task.Factory.StartNew(MainTask);
newTask.ContinueWith ((Task someTask) =>
{
Console.WriteLine ("Main State=" + someTask.Status.ToString () + " IsFaulted=" + someTask.IsFaulted+" isComplete="+someTask.IsCompleted);
});
while (true)
{
}
}
static async Task MainTask()
{
Console.WriteLine ("MainStarted!");
Task someTask = Task.Factory.StartNew (() =>
{
Console.WriteLine ("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine ("SleepEnded!");
});
await someTask;
Console.WriteLine ("Waiting Ended!!");
throw new Exception ("CustomException!");
Console.WriteLine ("NeverReaches here!!");
}
I just want to get Exception from new started task MainTask
. But the result was not what I was expected.
MainStarted!
Main State = RanToCompletion IsFaulted = False isComplete = True
SleepStarted!
SleepEnded!
Waiting Ended!!
As you can see the result, task finishes before "Waiting Ended!!" console log.
I don't have a clue that why MainTask
ended even if in MainTask
has await
command inside?
Did I missed something?
Upvotes: 14
Views: 673
Reputation: 63722
There's great answers here, but I'd like to point out the obvious - the Task.Factory.StartNew
is completely redundant, unnecessary and used wrong.
If you replace
Task newTask = Task.Factory.StartNew(MainTask);
with
Task newTask = MainTask();
You'll get exactly the behaviour you expect, without wasting yet another threadpool thread just to start another threadpool thread. In fact, if you wanted to rewrite your example to be more idiomatic, you'd use something like this:
static void Main (string[] args)
{
var task =
MainTask()
.ContinueWith(t => Console.WriteLine("Main State={0}", t.Status));
task.Wait();
}
static async Task MainTask()
{
Console.WriteLine ("MainStarted!");
await Task.Delay(1000);
Console.WriteLine ("Waiting Ended!!");
throw new Exception ("CustomException!");
Console.WriteLine ("NeverReaches here!!");
}
This code only uses a thread pool thread for the code after the delay, and rethrows the exception on the task.Wait()
call - you might want to do something else, of course.
As a side-note, even if you don't want to explicitly wait for the task to complete, you shouldn't use while (true) {}
to prevent the application from terminating - a simple Console.ReadLine()
will work just as well, and isn't going to push one of your CPU cores to 100% utilization :)
Upvotes: 6
Reputation: 10226
I modified your problem here to catch the exceptions.
static void Main(string[] args)
{
DoFoo();
Console.ReadKey();
}
static async void DoFoo()
{
try
{
await Foo();
}
catch (Exception ex)
{
//This is where you can catch your exception
}
}
static async Task Foo()
{
await MainTask().ContinueWith((Task someTask) =>
{
Console.WriteLine("Main State=" + someTask.Status.ToString() + " IsFaulted=" + someTask.IsFaulted + " isComplete=" + someTask.IsCompleted);
}, TaskContinuationOptions.NotOnFaulted);
}
static async Task MainTask()
{
Console.WriteLine("MainStarted!");
Task someTask = Task.Run(() =>
{
Console.WriteLine("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine("SleepEnded!");
});
await someTask;
throw new Exception("CustomException!");
Console.WriteLine("Waiting Ended!!");
}
you should use TaskContinuationOptions.NotOnFaulted
which means that the continue with task will only execute if the parent task did not had any exceptions.
Upvotes: 1
Reputation: 13495
Task.Factory.StartNew
does not understand async delegates so you need to use Task.Run
in this case and the exception should flow through.
Task.Factory.StartNew(MainTask);
is essentially equivalent to
Task.Factory.StartNew(() => MainTask);
which ignores the returned task from MainTask
and the exception just gets swallowed.
See this blog post for more details.
Try using Task.Run
instead and you'll get your exception:
void Main(string[] args)
{
Task newTask = Task.Run(MainTask);
newTask.ContinueWith((Task someTask) =>
{
Console.WriteLine("Main State=" + someTask.Status.ToString() + " IsFaulted=" + someTask.IsFaulted + " isComplete=" + someTask.IsCompleted);
});
while (true)
{
}
}
static async Task MainTask()
{
Console.WriteLine("MainStarted!");
Task someTask = Task.Run(() =>
{
Console.WriteLine("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine("SleepEnded!");
});
await someTask;
Console.WriteLine("Waiting Ended!!");
throw new Exception("CustomException!");
Console.WriteLine("NeverReaches here!!");
}
Upvotes: 17