5

I wonder why in a console app, if I spin a new thread to run from Main, even though Main will reach the end it will wait, though if I spin up a new task, it will exit and not wait for the task to end.

e.g.

static void Main(string[] args) 
{
    Thread t = new Thread(new ThreadStart(SomeMethod));
    t.Start();            
    // Main will wait, and app won't close until SomeMethod finishes
}

vs.

static void Main(string[] args)
{
    Task.Run(() => SomeMethod());
    // Main will close / app shuts down without waiting for SomeMethod to finish
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Maverick Meerkat
  • 5,737
  • 3
  • 47
  • 66
  • You have to `await` Task to complete otherwise Main will stop. – Valentin P Jul 03 '18 at 14:04
  • 1
    @ValentinPapin You cannot await in a static method such as Main – Ross Miller Jul 03 '18 at 14:05
  • 1
    See the [Thread.IsBackground](https://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396) property. – Michael Liu Jul 03 '18 at 14:05
  • Possible duplicate of [What is the difference between task and thread?](https://stackoverflow.com/questions/4130194/what-is-the-difference-between-task-and-thread) – Owen Pauling Jul 03 '18 at 14:06
  • @MichaelLiu explaining the difference between using the `Thread` constructor vs. the `ThreadPool` (which is used by `Task`) should be the answer to this. – Patrick Roberts Jul 03 '18 at 14:12
  • 1
    @PatrickRoberts probably a dupe of this then (covered in accepted answer) https://stackoverflow.com/questions/230003/thread-vs-threadpool – Owen Pauling Jul 03 '18 at 14:15
  • 1
    Possible duplicate of [Thread vs ThreadPool](https://stackoverflow.com/questions/230003/thread-vs-threadpool) – Patrick Roberts Jul 03 '18 at 14:17
  • A useful term to talk about code like this is *fire-and-forget*. The code doesn't check if SomeMethod is already running, doesn't use a result produced by that method, doesn't check if it failed with an exception. The CLR is equally happy to forget about it, no reason to keep the program running when the main thread terminates. Fire-and-forget is not often correct, especially an unobserved exception makes it awfully hard for a user to figure out why "it didn't work". – Hans Passant Jul 03 '18 at 14:47

2 Answers2

5

When reading the documentation for the Thread.IsBackground property, you'll notice there are two types of threads, background and foreground:

... background threads do not prevent a process from terminating. Once all foreground threads belonging to a process have terminated... any remaining background threads are stopped and do not complete.

The reason why the Thread constructor prevents the Main process from terminating is because by default, it creates foreground threads, while task-based asynchronous operations automatically execute on the ThreadPool, which uses background threads by default, and will allow the process to terminate before they are completed.

Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
-3

You have set SomeMethod to run on a different thread so it's now asynchronous. You aren't waiting for the result so Main will just continue and just exit, killing both threads in the process.

Use:

Task.Run(async () => await SomeMethod());

Assuming SomeMethod is awaitable otherwise you can just await the result externally

Task.Run(() => SomeMethod()).Result;
Ross Miller
  • 656
  • 3
  • 9
  • 2
    this does not answer my question. Thread.Start() doesn't wait either, yet the program waits until the thread execution is finished. – Maverick Meerkat Jul 03 '18 at 15:14