5

I have the following.

public static Thread testThread = new Thread(ThreadStart) {Name = "TestThread", IsBackground = true};
private void Form_Load()
{
    testThread.Start()
}
private static void ThreadStart()
{
    int count = 0;
    try
    {
        while (true)
        {
            count++;
        }
    }
    catch (Exception ex)
    {

        StreamWriter stream = new StreamWriter(File.OpenWrite("Exception.txt"));
        stream.WriteLine(count + "\n" + ex);
        stream.Flush();
        stream.Close();
    }
}

When I call Thread.Abort() I catch the exception and write out to the file. However, if I instead close the application nothing is written. I also have

AppDomain.CurrentDomain.UnhandledException +=
   new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
Application.ThreadException +=
   new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

But it doesn't appear an exception is ever thrown.

I suppose adding a question is prudent.

What happens to a running background thread when the parent processes exits? My understanding was a ThreadAbortException is thrown to exit the thread. If this is the case, how can the ThreadAbortException be caught in order to clean up resources that may be present in the thread?

galford13x
  • 2,483
  • 4
  • 30
  • 39
  • 2
    How are you starting the thread? Why would you expect a ThreadAbort to be thrown? And what is the question? – Chris Shain Feb 05 '12 at 20:06
  • From all my reading, when an application exits, all background threads that are running are aborted via a ThreadAbortException. I start the thread using the Thread.Start(ThreadStart) – galford13x Feb 05 '12 at 20:10
  • @Chris: Here is where I received some of my information. http://stackoverflow.com/questions/1354196/can-i-safely-rely-on-isbackground-in-threads-when-the-application-terminates – galford13x Feb 05 '12 at 20:12
  • Why are you using `Thread.Abort()`. Murdering threads is bad, m'kay? Better convince them to commit suicide, so you don't go to jail. – CodesInChaos Feb 05 '12 at 20:38
  • @CodeInChaos: It is an educational excercise. But a question to you would be, would you consider making a thread a Background thread then exiting the application murder? I have seen this done in many examples and libraries and always wondered why they didn't use different patterns to resolve ending the thread more gracefully. That is why I'm asking the question now. – galford13x Feb 05 '12 at 20:42

3 Answers3

4

First of all, the application probably isn't exiting, because you are not making these into background threads. My guess is that Task Manager will show copies of your EXE running unexpectedly. You need to set Thread.IsBackground to true on the thread object before calling Start.

Secondly, the behavior that you expect is explicitly debunked by the documentation:

Note

When the common language runtime (CLR) stops background threads, after all foreground threads in a managed executable have ended, it does not use System.Threading.Thread.Abort. Therefore, you cannot use ThreadAbortException to detect when background threads are being terminated by the CLR.

EDIT:

When a process is exiting, there is no need to clean up resources held by the worker threads because, you know, the process is exiting. The contract with regard to background threads is that they can be killed at any time when the process exits. Therefore, if your background threads are doing something that requires transactional correctness, they probably should not be background threads. Make 'em foreground threads and have them periodically check or wait on a reset event to see whether they should exit and allow the process to end.

Community
  • 1
  • 1
Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • Why is it not a background thread. I'm setting the property IsBackground = true when I initialize the thread. I will double check that this is true now. – galford13x Feb 05 '12 at 20:24
  • I have double checked while debugging and the IsBackground for testThread is in fact true. – galford13x Feb 05 '12 at 20:25
  • 2
    In that case, see the documentation I mentioned above. MSDN wins over some guy's opinion on stack overflow 99999 times out of 100000. – Chris Shain Feb 05 '12 at 20:27
  • My purpose is for educational purposes in understanding the difference between background and foreground threads. I have used libraries in the past that relied on background threads to exit via application exit. As to resources being released when the application exits, this is not entirely true. I have had applications that have opened files but exited prematurely hold the file lock even with no process listed in TaskManager. The only way to release the lock was to use specific tools or reboot the system. – galford13x Feb 05 '12 at 20:30
  • AFAIK that isn't possible in Windows. Could be wrong. It certainly isn't possible using the .NET I/O constructs. The only thing that is special about background threads in .NET is that they will not keep the process alive. – Chris Shain Feb 05 '12 at 20:32
  • Good point I misunderstood some of the post in the previous stackoeverflow as there was a quote from MSDN also. After rereading, I realized it did not actually saw an exception was thrown to stop the thread, only that the thread was stopped. It doesn't state how this is done. – galford13x Feb 05 '12 at 20:35
  • I have had a program lock a file in windows even after it exited. While I may not see the process listed in the taskmanager, it may be some rogue/child process that was started and I just don't know what to look for. using something like http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx, can allow you to find the culprit and free the resource. – galford13x Feb 05 '12 at 20:39
  • Your reference to MSDN documentation is closest to what I was looking for, however I would like to know how the CLR accomplishes the shutdown. Knowing that I can't detect the shutdown of the background is quite useful though. Thanks you for your help. – galford13x Feb 05 '12 at 20:49
  • Might want to check out this article on hosting the CLR: http://msdn.microsoft.com/en-us/magazine/cc163567.aspx#S3. It's not super detailed, but it should point you in the right direction. – Chris Shain Feb 05 '12 at 20:57
  • Thanks Chris I'll check it out. – galford13x Feb 05 '12 at 21:57
4

When the CLR shuts down a process it does not call Thread.Abort or anything similar. Your thread methods will not exit like your main method.

  1. The first thing it does when you leave the main method or call Environment.Exit is to finalize all objects with a timeout (it was 2s in .NET 2.0) then it will continue to terminate the application regardless of the current pending finalizers.
  2. Next the Critical Finalizers are called.
  3. Then all threads are suspended so they do not cause harm while the CLR is shutting down.
  4. You application has exited.
Alois Kraus
  • 13,229
  • 1
  • 38
  • 64
1

If the IsBackground property of your thread is false, then your thread would remain alive, even when the main window of your application is closed.

The best way to control the lifetime of background threads is to create sentinels, typically implemented as volatile bool fields, which the code within the thread checks at regular intervals (for example, on every iteration). The thread should stop executing when the sentinel indicates that the application is terminating.

The following code shows the use of a sentinel to terminate the thread after 200 milliseconds:

public static Thread testThread = new Thread(ThreadStart) 
{
    Name = "TestThread", 
    IsBackground = false    // Allow thread to terminate naturally
};

private static volatile bool isTerminating = false;   // Sentinel

private void Form_Load()
{
    testThread.Start();
    Thread.Sleep(200);      // Sleep 200 milliseconds
    isTerminating = true;   // Set sentinel to terminate thread
}

private static void ThreadStart()
{
    int count = 0;

    while (!isTerminating)   // Keep looping until sentinel is set
        count++;

    using (StreamWriter stream = new StreamWriter(File.OpenWrite("Result.txt")))
    {
        stream.WriteLine(count);
        stream.Flush();
    }
}

Edit: To answer your last question, “How can the ThreadAbortException be caught in order to clean up resources that may be present in the thread?” You can use an ordinary catch block. ThreadAbortException may be caught like any other exception, but it will automatically be raised again at the end of the catch block. However, as Chris mentioned, if the process is exiting, the ThreadAbortException is not raised at all.

Douglas
  • 53,759
  • 13
  • 140
  • 188
  • As shown it is set to true. Take notice that new Thread(ThreadStart) {isBackground = true}; I will double check however to see if before starting the thread it is true. – galford13x Feb 05 '12 at 20:21
  • I understand the general Thread execution pattern. But this is for more educational purposes in understanding what happens when a background thread exits. I have used libraries that rather than use good Thread patterns, they rely on IsBackground thread to exit the thread. – galford13x Feb 05 '12 at 20:23