2

I'm currently trying to work out how best to run a .NET Core 2.x application as a Windows Service, specifically to run an NServiceBus endpoint for a messaging system. My original prototype was built from some of the Windows Service hosting docs from Particular. I then took that functioning prototype and turned it into a .NET Standard library for other team members to build from, but found that it wasn't super intuitive for them (or myself if I looked away from it for 2 weeks).

Naturally, after I built a functioning prototype and it was deployed to production, I found a more elegant solution that uses .NET Core's GenericHostBuilder, courtesy of a Mr. Steve Gordon. The majority of the code makes sense to me, but I'm hung up on the new Thread(...).Start();, likely because I don't have any specific experience with using Thread in C# and .NET.

  1. newing up a Thread and maintaining no reference to it feels really wrong. I'm concerned that doing that might lead to a memory leak or the Garbage Collector will pick it up? I did find this SO answer which gives me some reassurance that even if I don't hold a reference to the Thread, the CLR will. So it sounds like there shouldn't be any concern of the GC finalizing the thread, right?
  2. Could anyone explain to me why Abort() is not called for the Thread? Is it because the CLR manages threads and knows to stop other threads when the main thread shuts down? Or is does it have something to do with calling the ServiceBase.Stop() method in the IHostLifetime.StopAsync() method?

If these things can be explained in some documentation of Thread somewhere, I'm more than happy to get an "RTFM" and find the docs. I just haven't found anything that's given me a clear explanation at this point.

willwolfram18
  • 1,747
  • 13
  • 25
  • 1
    Writing a multithreaded C# program correctly is extremely difficult and you do not understand even the very basics. **Find an expert to help you**. You will get it wrong, and worse, it will be wrong in subtle ways that do not show up in testing, but do in production. – Eric Lippert Sep 21 '18 at 18:03
  • I promise you I know the basics of multithreaded programming and understand that multithreaded programs can result in difficult to detect bugs (I've written a few multithread things and seen this myself). However you're correct that I have not yet used C# for multithreading. – willwolfram18 Sep 21 '18 at 18:50
  • And better yet, instead of telling me to "Find an expert" maybe point me to some docs or material to read so that I can learn and grow myself? Perhaps I don't have "an expert" with C# multithreading available? – willwolfram18 Sep 21 '18 at 18:58
  • 2
    Asking for off-site tutorials is **explicitly off topic for this web site**. That said, the threading chapters in *C# in a Nutshell* are very good. I was the editor of a recent edition. – Eric Lippert Sep 21 '18 at 18:59

1 Answers1

5

When a threads execution has finished and falls out of scope the, garbage collector will eventually reclaim the resources (when if feels the need). Thread also doesn't implement IDisposable so you really don't need to bother yourself with it hanging around (unless you are executing endless loops within it)

In regards to Thread.Abort vs Thread.Interrupt, My honest answer is that you should never use either of these methods to terminate a thread. It is advisable not to use Thread.Abort or Thread.Interrupt methods at all - you should rather take advantage of synchronization objects (like, WaitHandles or Semaphores, etc, etc, etc) and perform a graceful termination of the threads you are using.

In the wise words of Eric Lippert (the resident CLR wizard)

In short, Thread.Abort is at best indicative of bad design, possibly unreliable, and extremely dangerous. It should be avoided at all costs; the only time you should ever even consider aborting a thread is in some sort of "emergency shutdown" code where you are attempting to tear down an appdomain as cleanly as possible.

Some additional reading

halfer
  • 19,824
  • 17
  • 99
  • 186
TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • So, effectively, a thread should reach a natural stopping point on it's own, and any synchronization should use common strategies like the ones you mentioned. And basically the `ServiceBase.Run(this)` will handle the necessary start/stop code that will cause the `Thread` to finish safely, right? – willwolfram18 Sep 21 '18 at 04:06
  • 1
    @willwolfram18 that's a fair enough interpretation – TheGeneral Sep 21 '18 at 04:19
  • Thought I'd throw in this as some additional reading as well (a link within your suggested post): https://stackoverflow.com/q/3699147/5884242 – willwolfram18 Sep 21 '18 at 04:27