2

If I have called multiple async functions that are still being awaited, and the program exits on the main thread, are the tasks still being awaited cleaned up automagically? Or, do I need to ensure tasks are manually cleaned up when the program exits?

Asking specifically when calling async functions, not using new Thread().

Also, in this specific case, Task is referring to System.Threading.Tasks.Task generated when calling an async function and awaiting a result.

Can't seem to find the answer in MSDN (unless I'm looking in the wrong place).

Denmark
  • 41
  • 3
  • question if you use `new Thread()` they are not cleaned "automagically". – KJanek Jan 28 '21 at 17:33
  • 2
    `async Task`s and threads created by `new Thread()` are totally different things. Furthermore with threads, you can also set the `IsBackground` property. Typically, when the `Main()` function exits, the runtime *does* wait for forground threads, but not for backgroundthreads or tasks [IsBackground](https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread.isbackground?view=net-5.0) And of course, if the runtime does not wait for threads/tasks to finish, they may be in some indeterminate state, which might lead to data corruptions. – derpirscher Jan 28 '21 at 17:41
  • The title of the question is not consistent with the body of the question. The title asks about tasks, the body about threads. Could you [edit] the question and fix either the title or the body? – Theodor Zoulias Jan 28 '21 at 18:33
  • @KJanek In this case I'm not using `new Thread()` – Denmark Jan 28 '21 at 19:19
  • A `Task` can represent *literally anything*. There's no possible way to speak to the behavior of any arbitrary task in this respect. – Servy Jan 28 '21 at 19:19
  • 1
    @TheodorZoulias updated the question and text. Hopefully it's more clear – Denmark Jan 28 '21 at 19:20
  • @derpirscher updated the post. Asking specifically about `async Task` – Denmark Jan 28 '21 at 19:55
  • No, there is nothing that needs to be cleaned-up when the program terminates, the OS brooms up. The much more typical problem with async code is that it terminates too soon, before the tasks are complete. Do consider that async isn't worth much when you have to worry about such basic issues, being explicit in your code helps you and everybody that reads your code. – Hans Passant Jan 28 '21 at 22:54

2 Answers2

0

are the tasks still being awaited cleaned up automagically?

If the tasks are awaited, the program is not going to exit before the tasks are completed. So if the program exits, this means that the tasks are not awaited. Or that they are awaited inside a task which is itself not awaited. Or that they are awaited inside an async void method, which is not awaited by definition (an async void method returns nothing that can be awaited).

So I am assuming that you are dealing with non-awaited tasks, or in other words with fire-and-forget tasks. These tasks in most cases are running on threads having the IsBackground property equal to true, or not running on any thread at all. These tasks will be terminated automatically, at an arbitrary execution point. It is not impossible however to start a task that runs on a foreground thread, in which case the program will terminate when the task completes, or when the program is killed from the task manager.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
  • 1
    Your first sentence is just false. It's entirely possible for a program to exit while there are incomplete tasks, even incomplete tasks with continuations assigned to them. – Servy Jan 28 '21 at 20:06
  • 1
    @Servy I am referring to awaited tasks, and by "awaited" I mean that the application's main thread will eventually wait them directly or indirectly. Maybe the word "rooted" communicates better than "awaited" what I am trying to say. – Theodor Zoulias Jan 28 '21 at 20:14
  • There's a *huge* difference between the phrase, "Tasks awaited by the main method" and "tasks that are awaited". If you meant the former, then you shouldn't have said the latter. Additionally, tasks awaited by the main method are irrelevant to a discussion of what happens to tasks that are incomplete when the main method is finished. If the main method awaits them then, *by definition*, they are not incomplete when the main method finishes. – Servy Jan 28 '21 at 20:17
  • @Servy the first paragraph of my answer constitutes an argument as a whole. Each sentense doesn't make sense individually. The OP referred to tasks that *"are still being awaited"*. My answer attempts to give a meaning to the word "awaited", that is probably different than the meaning that the OP gives to it. But honestly I think that the OP will probably be more interested about the second paragraph of my answer than the first. – Theodor Zoulias Jan 28 '21 at 20:33
  • And your "argument as a whole" relies on claims that you makes that are inaccurate. Thus the argument as a whole isn't sound. – Servy Jan 28 '21 at 20:37
  • @Servy I tried my best to form this argument, I am reading it again multiple times, and I cannot see any way to improve it. It's sad that you don't like it, but I can't do much about it. – Theodor Zoulias Jan 28 '21 at 20:51
  • You really can't see the difference between "a task that's awaited by the main method" and "a task that's awaited", and you really think they're the same thing? Do you think the main method is the only place that you can await anything? – Servy Jan 28 '21 at 21:12
  • 1
    @Servy in this answer I am using a more restrictive definition of "awaited". I consider "awaited" to be the opposite of fire-and forget, so it excludes tasks that are not part of an `await` chain that reaches the `Main` method. The reason that I adopted this definition is because the OP referred to tasks that "are still being awaited", not to tasks that are "still being running". This indicates that they may have some extra expectations from the fact that their tasks are not only running, but they are also awaited. The first paragraph of this answer attempts to address these expectations. – Theodor Zoulias Jan 28 '21 at 21:39
  • But that's not what that means. It means something very different from that. Saying that you're using a radically different definition of a word than everyone else is using doesn't make it a correct statement. People are going to assume words mean what everyone else thinks they mean, rather than what only you think they mean. – Servy Jan 29 '21 at 02:14
  • @Servy I am willing to adopt a better terminology, if one exists. What name would you give to the concept of "being part of an `await` chain that reaches the `Main` method"? – Theodor Zoulias Jan 29 '21 at 08:27
  • "being part of an `await` chain that reaches the `Main` method" would be accurate. – Servy Jan 29 '21 at 14:18
  • 2
    @Servy yes, but replacing every instance of "awaited" in my answer with this 11-word phrase, would make for an absolutely terrible answer. Could you propose a shorter way to describe this concept? "Being part of an `await` chain that reaches the `Main` method" is a pretty important concept, so it deserves a usable name, don't you think? – Theodor Zoulias Jan 29 '21 at 14:32
  • It's not important to a discussion of what happens to incomplete tasks when the main method ends because *those tasks are not complete when the main method ends, by definition*. If you think making correct statements about an irrelevant topic by writing out 11 words is too much of a waste of your time, then imagine how much the answer would be removed by removing the entirety of an irrelevant topic.. But if you for some reason, *do* think it's important to talk about tasks awaited directly or indirectly by the main thread, then *at least talk about them accurately*. – Servy Jan 29 '21 at 16:35
  • Talking about something irrelevant is confusing and makes for a poor answer, but making inaccurate statements that lead to false conclusions about irrelevant topics is *much worse*, so if you disagree with me and think it's important to talk about it, at least make the statements accurate. Making the statements concise comes after them being correct, not before. – Servy Jan 29 '21 at 16:39
  • Thanks @Servy for sharing your thoughts. I may come back and edit this answer, when a generally accepted term has been established for the aforementioned concept. – Theodor Zoulias Jan 29 '21 at 17:52
  • So because you don't like the actually correct term for what you're referring to, you're just going to use a *different* term that means something radically different because you can't be bothered to use the *correct* term because you don't like how the correct term sounds? That makes no sense whatsoever, and is just wildly inconsiderate of everyone tricked into thinking what your answer says is actually correct. – Servy Jan 29 '21 at 19:01
-1

https://medium.com/@hasangi/lets-talk-about-parallelism-in-net-baby-2a69ba53f986

Threads are created as foreground processes by default(can be set to run in the background) and Tasks are created as background processes. An application will not terminate when any foreground processes are running. However, an application will terminate when all foreground processes complete even though when background processes are running. Hence a Task will terminate even without completing.

If we can't create a task running in a foreground thread then the answer is yes, non-awaited tasks will always be terminated on program exit.

C.M.
  • 1,474
  • 13
  • 16
  • 2
    At least 3/4 of what's in that source is just factually inaccurate, you should not rely on that source at all. – Servy Jan 28 '21 at 20:29
  • You can find [here](https://stackoverflow.com/questions/16720496/set-apartmentstate-on-a-task/) an example of how to create a task that runs on a foreground thread. – Theodor Zoulias Jan 28 '21 at 21:04