Automatically terminating non-essential threads in C #

I have an object in C # on which I need to execute a method on a regular basis. I would like this method to be executed only when other people use my object, as soon as people stop using my object. I would like this background operation to stop.

So here is a simple example: this (which is broken):

class Fish { public Fish() { Thread t = new Thread(new ThreadStart(BackgroundWork)); t.IsBackground = true; t.Start(); } public void BackgroundWork() { while(true) { this.Swim(); Thread.Sleep(1000); } } public void Swim() { Console.WriteLine("The fish is Swimming"); } } 

The problem is that if I am new to the Fish object anywhere, it will never collect garbage because there is a background thread referencing it. Here is an illustrated version of the broken code.

 public void DoStuff() { Fish f = new Fish(); } // after existing from this method my Fish object keeps on swimming. 

I know that the Fish object must be disposable, and I must clear the stream at the disposal, but I do not control my subscribers and cannot guarantee that dispose is called.

How can I get around this problem and ensure that background threads are automatically deleted, even if Dispose is not explicitly called?

+3
source share
3 answers

Here is my suggested solution to this problem:

 class Fish : IDisposable { class Swimmer { Thread t; WeakReference fishRef; public ManualResetEvent terminate = new ManualResetEvent(false); public Swimmer(Fish3 fish) { this.fishRef = new WeakReference(fish); t = new Thread(new ThreadStart(BackgroundWork)); t.IsBackground = true; t.Start(); } public void BackgroundWork() { bool done = false; while(!done) { done = Swim(); if (!done) { done = terminate.WaitOne(1000, false); } } } // this is pulled out into a helper method to ensure // the Fish object is referenced for the minimal amount of time private bool Swim() { bool done; Fish fish = Fish; if (fish != null) { fish.Swim(); done = false; } else { done = true; } return done; } public Fish Fish { get { return fishRef.Target as Fish3; } } } Swimmer swimmer; public Fish() { swimmer = new Swimmer(this); } public void Swim() { Console.WriteLine("The third fish is Swimming"); } volatile bool disposed = false; public void Dispose() { if (!disposed) { swimmer.terminate.Set(); disposed = true; GC.SuppressFinalize(this); } } ~Fish() { if(!disposed) { Dispose(); } } } 
+4
source

I think the IDisposable solution is correct.

If users of your class do not follow the recommendations for using classes that implement IDisposable, this is their mistake, and you can make sure that the documentation explicitly indicates how the class should be used.

Another, much messier option would be the DateTime "KeepAlive" field, which will update every method called by your client. The workflow then periodically checks the field and exits if it has not been updated for a certain amount of time. When the method sets the field, the thread will restart if it exits.

+2
source

Here's how I do it:

 class Fish3 : IDisposable { Thread t; private ManualResetEvent terminate = new ManualResetEvent(false); private volatile int disposed = 0; public Fish3() { t = new Thread(new ThreadStart(BackgroundWork)); t.IsBackground = true; t.Start(); } public void BackgroundWork() { while(!terminate.WaitOne(1000, false)) { Swim(); } } public void Swim() { Console.WriteLine("The third fish is Swimming"); } public void Dispose() { if(Interlocked.Exchange(ref disposed, 1) == 0) { terminate.Set(); t.Join(); GC.SuppressFinalize(this); } } ~Fish3() { if(Interlocked.Exchange(ref disposed, 1) == 0) { Dispose(); } } } 
+2
source

All Articles