2

When Thread.Abort() is called, and that thread is executing finally block, then thread won't abort until finally block is finished. But, as i see, ThreadAbortException is generated not right after the end of finally block, but after some delay:

private static volatile int val1 = 0;

public static void Func1()
{
    try
    {
    }
    finally
    {
        Thread.Sleep(5000);
    }
    //Func2();

    while (true)
        val1++;
}

public static void Main()
{
    var thread = new Thread(Func1);
    thread.Start();

    Thread.Sleep(1000);

    thread.Abort();
    thread.Join();

    Console.WriteLine(val1);  // val1 is non-zero!
}

In this example, val1 at the end of Main() will be non-zero. Why does it happen?

If i uncomment call to Func2() (Func2 is any method, possibly empty), output for val1 will show "0". Why does adding of method affect point of thread abortion?

Domanser
  • 33
  • 5
  • Interesting question, however in release mode without the debugger attached I can get a Non-zero number for `val1` too `Func2()` uncommented with a Empty function. With the debugger attached in release or in Debug with our without the debugger all give me 0. – Scott Chamberlain Oct 22 '14 at 22:35
  • `Thread.Abort` is **bad**, very **bad**. It **will** leave your application in an unpredictable state, and you won't be able to rely on the common assumptions about program behavior after using it. You should [avoid](https://stackoverflow.com/questions/1559255/whats-wrong-with-using-thread-abort) calling it at all costs. – Bradley Uffner Nov 14 '17 at 14:34

1 Answers1

0

In this case it could be usefull to surround the increment with a lock. The lock controlls the access on that member. The Abort method just notify the thread "Hey, you can stop now" but it does not kill the Thread. So the thread can be alive for a few moments after the Abort. Accessing the lock the thread checks if it got aborted and kills it self if needed.

Here is your example code edited

using System;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        private static volatile int val1 = 0;
        static Object Locker = new Object();

        public static void Func1()
        {
            try
            {
            }
            finally
            {
                Thread.Sleep(5000);
            }
            //Func2();

            while (true)
            {
                //Lock the access to the member
                lock (Locker)
                    val1++;
            }
        }

        public static void Main()
        {
            var thread = new Thread(Func1);
            thread.Start();

            Thread.Sleep(1000);
            //Not needed. Just to make sure
            lock (Locker)
            {
                thread.Abort();
                thread.Join();
            }

            Console.WriteLine(val1);  // val1 is non-zero!
                                      // Now it is zero
            Console.ReadLine();
        }
    }
}

Sorry for late answer

Kotentopf
  • 21
  • 1
  • `Thread.Abort` can abort a thread in the middle of a locked region. If this happens, **it will not release the lock**. This is extremely dangerous advice. – Bradley Uffner Nov 14 '17 at 14:38
  • It will release the lock, cause the release of a lock is internal in a finally block and finally blocks will always executed if the thread aborts in one situation with finally, as the thread actually get kileld cause of a ThreadAbortException. You also could just handle that exception instead. Check [this](https://stackoverflow.com/a/18002756/8939287) – Kotentopf Nov 15 '17 at 15:21
  • That isn't always true. If the thread aborts *during* the finally block, it can skip releasing the lock. See the discussion [here](https://stackoverflow.com/questions/1559255/whats-wrong-with-using-thread-abort), with the some of the people that actually designed C# and .NET. – Bradley Uffner Nov 15 '17 at 15:24