0

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

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

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

我使用IDisposable/using模式或 catchThreadAbortException来保证所有资源都被释放并停止异步操作。

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

如果线程在执行代码时被中止,是否有任何 .net 类(例如FileStream, )会导致问题?Dictionary还是我应该注意的其他一些问题?

4

1 回答 1

1

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

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

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

public IDisposable CreateThing() => null;

并查看生成的 C# 和 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语句使用了一个重载,Monitor.Enter它返回一个布尔值,表示锁是否被实际获取,并且:

lock (lockObject)
{
}

编译为:

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

为了避免这个问题。

但是,当使用任何其他同步方法时,您不会得到这种奢侈 - 仅lock- 因此您很容易死锁。

于 2019-04-24T09:05:43.530 回答