Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implicitly stop a thread in an object in C#

Tags:

c#

dispose

I have an object that contains a working thread. I'd like to kill the thread when the object is out of scope.

using System.IO;
using System;
using System.Threading;

namespace tt {
    class Program
    {
        static void Main()
        {
            AnotherClass a = new AnotherClass();
            a.Say();
        }

    }

    class AnotherClass:IDisposable {
        private bool m_Disposed;
        private readonly AutoResetEvent m_ResetEvent = new AutoResetEvent(false);

        public AnotherClass() {
            Thread t = new Thread(wait);
            t.Start();
        }

        public void Dispose() {
            Dispose(true);
        }
        private void Dispose(bool disposing) {
            if (m_Disposed) {
                return;
            }

            if (disposing) {
                Console.WriteLine("inner disposing");
            }
            m_ResetEvent.Set();
            Console.WriteLine("Outer disposing");
            m_Disposed = true;
        }

        private void wait() {
            m_ResetEvent.WaitOne();
        }

        ~AnotherClass() {
            Dispose(false);
        }

        public void Say() {
            Console.WriteLine("HellO");
        }
    }
}

The program will just hang in there because the destructor of AnotherClass is not called. I know I can call a.Dispose() to kill the thread. But is there a way to implicitly kill the thread when the object goes out of scope?

like image 527
Monster Hunter Avatar asked Aug 19 '15 18:08

Monster Hunter


3 Answers

No, that's not possible. There is no reference counting that can notice that the object has no more references, so there is no way to do anything when that happens.

The IDisposable interface is used for classes that needs to do something when an instance is not going to be used any more, and calling the Dispose method is how you signal that you are done with the instance.

The usual way to make sure that an object is disposed when you leave a scope is to wrap the code in a using block:

static void Main()
{
  using (AnotherClass a = new AnotherClass())
  {
    a.Say();
  }
}

The using block is syntactic sugar for a try...finally block:

static void Main()
{
  AnotherClass a = new AnotherClass();
  try
  {
    a.Say();
  }
  finally
  {
    if (a != null)
    {
      ((Idisposable)a).Dispose();
    }
  }
}
like image 83
Guffa Avatar answered Oct 19 '22 14:10

Guffa


Adding to Guffa's answer, I think it's also important to note that even if you had a way to detect the precise moment that your AnotherClass instance went out out scope, in this case, it just never will. And that's why you noticed that your destructor never got called.

The reason for that is that when you create and start your working thread, the thread is passed a delegate reference pointing to the instance method wait() which comes with an implicit reference to this (the AnotherClass instance). So as long as your thread does not itself go out of scope, it will hold a strong reference to the AnotherClass instance and prevent it from getting garbage collected.

like image 2
sstan Avatar answered Oct 19 '22 15:10

sstan


You could use exception handling and use the error displayed as the exception in the catch block

like image 1
Mudassir Dehghani Avatar answered Oct 19 '22 14:10

Mudassir Dehghani