This is actually a pretty confusing topic. One reason why we all harp about Thread.Abort
is because it injects an asynchronous exception into the target thread. The injection is nondeterministic and can often be at an unsafe point. It could occur immediately after acquiring a resource (lock, unmanaged resource, etc.) causing a resource leak or leaving a lock in an acquired state. The CLR has some provisions for mitigating the risk by attempting to delay the injection in some very intricate ways during the execution of try-catch-finally blocks. Unfortunately, there is no fail-safe way to guarentee all of the scenarios involved when calling Thread.Abort
and I suspect the vast majoring of the edge cases lie in the unmanaged code realm. For this reason I advise against aborting threads.
Instead your should design your plugin so that it runs in a separate AppDomain
and accepts shutdown requests so that it has a chance to gracefully end on its own. There would be some marginal level of protection by using a separate application domain since you could, as a last resort, abort a misbehaving thread and then tear down the AppDomain
in which the thread was executing code. Again, there is no guarentee that this will completely isolate the potential for corrupted state caused by the abort. The only fail-safe design is to run the plugin in its own process.
Unrelated to the abort problem there a couple of things you need to do to make sure the unmanaged resource is released. First, implement a finalizer so that in the absence of calling Dispose
the finalizer should do it eventually. Second, and I am not sure what level of protection this actually provides, call GC.SuppressFinalize
after the call to the private Dispose(bool)
method. If an ansynchronous exception were to get injected in the public Dispose
method you do not want the object removed from the finalization queue. Again, I am not sure how much that is going to help because your object may now be in a corrupted state which would prevent the second attempt at releasing the resource. Third, if possible use one of the CriticalFinalizerObject
or SafeHandle
classes to wrap the resource as this adds further protection through the use of Constrained Execution Regions.