我正在为大型系统编写插件。系统在一个独立的线程中运行我的插件。在插件内部,我正在分配一个非托管资源。我需要100%确定我发布了这个驱动程序。我实现了IDisposable模式,如果插件即将被终止,我将覆盖系统声称要调用的所有方法。
我有点担心这种情况,当系统出于任何原因退出我的线程(Abort,或其他)。我可以在插件中做更多的事情来确保释放非托管资源吗?
E.g。如果我在VS中停止调试,资源仍未发布(我知道这是一个愚蠢的例子)。
答案 0 :(得分:1)
在.NET下,线程终止时无法运行代码。你能做的最好就是写一个终结器,并希望在合理的时间范围内调用它。
答案 1 :(得分:1)
您需要同时实现终结器和IDisposable
,这样如果由于任何原因Dispose
未被调用(线程中止),GC将释放它。
所以你的终结者会调用你的Dispose方法:
class MyClass : IDisposable
{
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing)
{
// release ...
}
~MyClass()
{
Dispose(false);
}
}
传递处置的原因是,如果最终确定,你知道不要碰任何状态。
答案 2 :(得分:1)
尝试捕获此异常: http://msdn.microsoft.com/en-us/library/system.threading.threadabortexception.aspx
如果资源尚未处理,请在那里进行处置。
答案 3 :(得分:1)
这实际上是一个令人困惑的话题。我们都关于Thread.Abort
的一个原因是因为它向目标线程注入异步异常。注射是不确定的,通常可能处于不安全的地步。它可能在获取资源(锁定,非托管资源等)后立即发生,从而导致资源泄漏或在获取状态下保持锁定。 CLR具有一些规定,通过在执行try-catch-finally块期间以一些非常复杂的方式延迟注入来降低风险。不幸的是,在调用Thread.Abort
时,没有任何故障安全的方法来保证所涉及的所有场景,我怀疑边缘案例的大量主要在于非托管代码领域。出于这个原因,我建议不要中止线程。
相反,你应该设计你的插件,使它在一个单独的AppDomain
中运行并接受关闭请求,以便它有机会自己优雅地结束。通过使用单独的应用程序域将有一些边际保护级别,因为作为最后的手段,您可以中止行为不当的线程,然后拆除线程正在执行代码的AppDomain
。同样,没有任何保证,这将完全隔离由中止导致的腐败状态的可能性。唯一的故障安全设计是在自己的进程中运行插件。
与中止问题无关,您需要做一些事情来确保释放非托管资源。首先,实现一个终结器,这样在没有调用Dispose
的情况下,终结器最终应该这样做。其次,我不确定这实际提供了什么级别的保护,在调用私有GC.SuppressFinalize
方法后调用Dispose(bool)
。如果要在公共Dispose
方法中注入异步异常,则不希望将对象从终结队列中删除。同样,我不确定这将有多大帮助,因为您的对象现在可能处于损坏状态,这将阻止第二次尝试释放资源。第三,如果可能的话,使用CriticalFinalizerObject
或SafeHandle
类中的一个来包装资源,因为这通过使用Constrained Execution Regions增加了进一步的保护。