如何正确使用Thread.Abort()?

时间:2019-04-24 08:54:46

标签: c# multithreading thread-safety threadabortexception thread-abort

线程中止时会导致什么问题?

我需要在代码中使用Thread.Abort(),因为该线程运行的复杂代码具有很多循环,对象和条件。

我知道Thread.Abort()在使用Monitor时会导致死锁,也可以防止资源被释放,但是我可以解决这些问题。

我使用IDisposable / using模式或捕获ThreadAbortException来确保释放所有资源并停止异步操作。

该应用程序现在似乎可以正常运行。但是,由于代码非常复杂,所以我不确定在中止线程时是否可能有一些罕见的情况会导致内存泄漏或未处理的异常。

是否存在任何.net类(例如FileStreamDictionary),如果在执行它们的代码时中止线程,它们可能会引起问题?还是我应该注意的其他一些问题?

1 个答案:

答案 0 :(得分:1)

Thread.Abort的问题在于您的ThreadAbortException可以在任何两个指令之间(几乎)抛出。

如果您使用一些非常简单的代码,例如:

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

public IDisposable CreateThing() => null;

看看generated C# and IL

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

您可以看到在调用CreateThing和进入try块之间有两条指令。有一个很小的机会窗口,如果正确调用Thread.Abort,您的对象将被处置。

因此,使用IDisposableusing不能不能保证面对Thread.Abort时您的资源被释放。

有很好的理由将Thread.Abort从.NET Standard中删除,以及为什么应使用CancellationToken

您应该使用CancellationToken,并且您的代码应检查是否已在适当的安全点将其取消(使用CancellationToken.ThrowIfCancellationRequested())。


顺便说一句,lock语句使用overload of Monitor.Enter返回布尔值,表明是否实际获取了锁,并且:

lock (lockObject)
{
}

编译为:

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

为避免这个问题。

但是,在使用任何其他同步方法(仅使用lock时),您就不会感到奢侈,因此您很容易死锁。