6

I was doing some tests with the TPL and async/await and noticed something that I find unexpected: I was scheduling work to run using lambdas and Task.Run, for instance:

Task.Run(()=>Console.WriteLine("Nice program"));

And then I realized that if program immediately returns the work is never executed. Is that the expected behavior in any .NET application (WPF, Forms, etc.)? Is there any documentation that discusses this?

This means that Task.Run is actually a no-go for fire-and-forget scenarios.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Bruno Brant
  • 8,226
  • 7
  • 45
  • 90
  • You may be lucky if that is run on the thread ExitProcess is being called, otherwise it i gone. Read [here](http://blogs.msdn.com/b/oldnewthing/archive/2007/05/03/2383346.aspx) – rene Jan 15 '13 at 20:21
  • @rene How Windows processes terminate is not that interesting when programming .Net applications, I think. – svick Jan 15 '13 at 21:27
  • @svick Well it depends I guess. You cann't expect a capability that the OS doesn't have to be available in framework that runs on top of that OS (and as this was not tagged Mono, linux is here not in play). So my comment is for sure not an answer but it might help to reason about or understand the behavior. At least it helps me... – rene Jan 16 '13 at 07:30

2 Answers2

12

This means that Task.Run is actually a no-go for fire-and-forget scenarios.

Well, you don't want to forget - you want to wait until it's completed. So use the Task that's returned to you.

To do that, you'll need to keep track of all uncompleted tasks that you launch this way, and then use something like Task.WaitAll(tasks) in a non-background thread. You potentially don't need to remember the tasks themselves - you just need to have a counter which is decremented when each task completes, and then you just need to wait for that to get to zero.

It's hard to give more concrete advice than that without knowing more about your scenario, to be honest... but something like that would certainly work.

You can easily encapsulate this in your own convenience methods, of course.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • What if the method execution has already begun? Is it aborted? – Bruno Brant Jan 15 '13 at 20:33
  • I was expecting it to behave somewhat close to a thread - the program don't exit until all threads have finished. I don't understand the conceptual difference between threads and what `Task.Run` is doing. – Bruno Brant Jan 15 '13 at 20:35
  • 1
    @BrunoBrant That's not true, program doesn't exit until all *foreground* threads have finished. The difference is that `Task`s normally run on background threads. – svick Jan 15 '13 at 21:26
  • 2
    @BrunoBrant: No, tasks aren't threads. They're generally closer to "thread pool operations". – Jon Skeet Jan 15 '13 at 22:32
3

By definition, after program terminates, no code can run. This has nothing to do with Task.Run().

If what you're actually asking is something like:

Tasks run on background threads, so if the main thread completes (e.g. after the user closes the main window), they are not guaranteed to run to completion or even start, how can I fix that?

Then there are two options: either don't let the main thread complete (e.g. by calling Task.WaitAll() as Jon Skeet suggests), or run your important Tasks on a foreground thread. To do that, you can use QueuedTaskScheduler from ParallelExtensionsExtras.

svick
  • 236,525
  • 50
  • 385
  • 514