0

I have a class that implements IDisposable. The class contains a thread and the thread is closed in the Dispose method using Thread.Join(...)

My issue however is that if I run my class like this:

static void Main(string[] args)
{
    var class = new MyClass();
    class.Run();
}

when the application closes, it forcefully closes the thread without waiting for it to finish execution.

However, if I run it like this:

static void Main(string[] args)
{
    using (var class = new MyClass())
    {
        class.Run();
    }
}

the thread finishes what it started and ends gracefully. What is the using statement doing that's allowing the thread to finish executing?

My hunch is that with the first method, because the application has exited, it forcefully closes the thread without waiting for it to finish. However, under the using block, the application is still running so it has time to close the thread then exit the application.

If my hunch is correct can you let me know why the application doesn't wait on the thread the be finished before closing?

Edit:

~ElasticBase()
{
    Dispose(false);
} 

public virtual void Initialize()
{
    workerThread = new Thread(ProcessData)
    {
        Name = "ElasticBase thread",
        IsBackground = true
    };

    IsInitialized = true;
}

public virtual void Shutdown()
{
    if (workerThread.IsAlive)
    {
        IsInitialized = false;
        lock (syncObject)
        {
            if (!workerThread.Join(10000))
            {
                workerThread.Abort();
            }
            workerThread = null;
        }
    }
}

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

protected void Dispose(bool calledFromDispose)
{
    Shutdown();
}

As you can see with the code above. The Shutdown method is called in Dispose. If I DON'T call Dispose explicitly and I DON'T use a using block, the Thread.Join method closes without finishing. However, if I do call Dispose explicity or use a using block, suddenly Thread.Join works as expected. Why?

TLDR;

When Dispose is invoked through the finalizer, Thread.Join doesn't wait to finish. When dispose is explicitly invoked (through manually calling it or with a using statement), Thread.Join waits to finish.

CodingMadeEasy
  • 2,257
  • 4
  • 19
  • 31
  • http://stackoverflow.com/questions/212198/what-is-the-c-sharp-using-block-and-why-should-i-use-it – Timothy Kanski May 27 '16 at 22:25
  • 1
    Is the thread in your class a background thread? If it's a foreground thread than in both cases the invoking thread should wait till the child thread finishes. If it's background thread then Thread.Join() forces the main thread to wait for the child thread to finish. Otherwise it finishes without waiting for child threads. – PiotrWolkowski May 28 '16 at 01:44
  • @PiotrWolkowski It is a background thread. But when I change it to a foreground thread. It exits even faster :/ – CodingMadeEasy May 28 '16 at 23:44
  • If you could show at least some code of your `MyClass` that would be helpful. Especially the method where the thread is created and started and the part where you use `Thread.Join`. – PiotrWolkowski May 28 '16 at 23:59
  • @PiotrWolkowski updated. – CodingMadeEasy May 30 '16 at 15:12
  • Finalizers aren't executed when a process is dying. Try writing a debug output in your finalizer - I'm pretty sure you'll get nothing :) That should only apply for a background thread, though - you might want to add the relevant code from your base class - there might be additional issues there. – Luaan May 30 '16 at 15:18

1 Answers1

-1

You're missing two pieces of information:

  • Thread.Join doesn't close the thread. Rather, it waits until the thread has finished executing.
  • using is just syntaxic sugar for calling the Dispose method in a try/finally block.

To make it simple, your code is equivalent to:

MyClass class = null;

try
{
    class = new MyClass();
    class.Run();
}
finally
{
    if (class != null)
    {
        class.Dispose();
    }
}

Since your Dispose method calls Thread.Join which in turn waits for the thread to finish executing, your application doesn't exit prematurely.

Kevin Gosse
  • 38,392
  • 3
  • 78
  • 94
  • But once Thread.join is called in my first example. The thread doesn't finish executing. Is it because the application is closed? Is it the application that's forcefully closing the thread? Also I know what using does but once I use it, the thread finishes executing. Even if I don't using the using statement but I called class.Dispose() before the application exits, the thread finishes executing. Yet when dispose is called by the finalizer, the thread abruptly closes. – CodingMadeEasy May 27 '16 at 22:36
  • @CodingMadeEasy In the first code you posted, `Dispose` is called nowhere – Kevin Gosse May 28 '16 at 07:53
  • @KoolKiz I know I haven't. I'm simply trying to state that when dispose is explicitly called (with using or Dispose method). The thread finishes executing. However if I don't use a using block and I don't explicitly call .Dispose(). The application forcefully exits without finishing the thread. – CodingMadeEasy May 28 '16 at 23:42
  • @CodingMadeEasy What I've trying to explain is that `Thread.Join` is the statement that makes your program wait until the thread has finished executing. Since you call `Thread.Join` in your `Dispose`, when you call Dispose your program will wait until the thread has finished. And `using` is just an elaborate way of calling `Dispose`, it's pretty much the same as if you called it manually – Kevin Gosse May 29 '16 at 09:12
  • I know how Dispose and using statements work. I know that a using statement is an elaborate statement way of calling dispose. What I'm trying to say is when I DON'T call dispose and I DON'T use a using statement, the finalizer still calls Thread.Join but doesn't wait for the thread to finish. – CodingMadeEasy May 30 '16 at 15:03
  • @KoolKiz I've updated my question to give more clarification. – CodingMadeEasy May 30 '16 at 15:13
  • 1
    @CodingMadeEasy There was no mention of the finalizer in the original question, so it was a bit hard to follow ;) During application shutdown, finalizers are given only a couple seconds to execute, to avoid blocking the app. http://stackoverflow.com/a/9941751/869621 – Kevin Gosse May 30 '16 at 18:44
  • @KoolKiz Ahh I see. Interesting! Thanks so much for the response and I'm so sorry for my question not being detailed originally. – CodingMadeEasy May 30 '16 at 19:45