简体   繁体   中英

How to use Thread.Abort() properly?

What can cause issues when thread is aborted?

I need to use Thread.Abort() in my code because the thread runs complex code that have a lot of loops, objects and conditions.

I know that Thread.Abort() can lead to deadlock when using Monitor , also it can prevent resources from being released, but I can handle these problems.

I use IDisposable / using pattern or catch ThreadAbortException to guarantee that all resources are released and asynchronous operations are stopped.

The application seems to works fine now. But, since the code is pretty complex, I'm not sure if there could be some rare cases when aborting the thread can lead to memory leaks or unhandled exceptions.

Is there any .net classes (eg FileStream , Dictionary ) that can cause problems if thread is aborted when their code are executed? Or some other issues that I should be aware of?

The problem with Thread.Abort is that your ThreadAbortException can be thrown between any two instructions (almost).

If you take some very simple code like:

public void M()
{
    using (CreateThing())
    {
    }
}

public IDisposable CreateThing() => null;

And look at the generated C# and IL :

public void M()
{
    IDisposable disposable = CreateThing();
    try
    {
    }
    finally
    {
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }
}

You can see that there's a couple of instructions between CreateThing being called, and it entering the try block. There's a small window of opportunity where, if Thread.Abort is called right then, your object will not be disposed.

So using IDisposable and using does not guarantee that your resources get freed in the face of Thread.Abort .

There is a very good reason why Thread.Abort was removed from .NET Standard, and why you should use CancellationToken instead.

You should use CancellationToken , and your code should check whether it's been cancelled (using CancellationToken.ThrowIfCancellationRequested() ) at suitable, safe points.


As an aside, lock statements use an overload of Monitor.Enter which returns a boolean saying whether the lock was actually acquired, and:

lock (lockObject)
{
}

compiles to:

bool lockTaken = false;
try
{
    Monitor.Enter(lockObject, ref lockTaken);
}
finally
{
    if (lockTaken)
        Monitor.Exit(lockObject);
}

to avoid exactly this problem.

However, you don't get this luxury when using any other synchronization methods - only lock - and so you can easily deadlock.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM