Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IDisposable implementation for the class which holds threads

Good morning! Let's assume we have the following class:

class MultithreadOperation : IDisposable
{
    private IList<Thread> operationThreads;

    public void StartOperation()
    {
          // Initialize and start threads and put them to operationThreads
    }

    public void StopOperation()
    {
          // Aborts each thread.
    }

    public void Dispose()
    {
          Dispose(true);
          GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
         if (!disposed)
         {
              disposed = true;
              if (disposing)
              {
                    // Release managed resources.
                    #1:
                    StopOperation();
              }
              // Release unmanaged resources.
              #2:
              StopOperation();
         }
    }

    ~MultithreadOperation()
    {
         Dispose(false);
    }
}

Actually, I need to stop all the threads if the instance is disposed. Also, I need to stop all the threads if the instance is garbage collected (otherwise, the threads will be still alive, which is bad for me). Definitely, it is totally legal to invoke StopOperation() method in place #1.

I want to know are there any pitfalls if we invoke StopOperation() in place #2 ? As I understand, the list of threads can be already garbage collected when the ~MultithreadOperation() is executing. Also, I've seen a lot of recommendations to avoid any code which refers to the managed resources in the Finalize implementation, especially the instance fields.

Also, It would be interesting to hear about different approaches for this problem. Thanks!

like image 815
Alexander Avatar asked Sep 28 '10 12:09

Alexander


1 Answers

This is completely inappropriate. A user of your class that doesn't know the details well will assume that calling Dispose() will do something innocent. A bit of cleanup, nothing fancy. She will not expect the program to be left in a completely unpredictable state with threads mutating that state aborted at random locations with no way to recover state.

It is also complete redrum on the finalizer thread, aborting a thread can take many seconds if the thread is not in an alertable state. The CLR will abort the finalizer thread after 2 seconds and terminate the program, giving no diagnostic at all about the true reason the program crashed.

like image 200
Hans Passant Avatar answered Oct 03 '22 08:10

Hans Passant