Do .NET finalizers have a timeout? - c#

Edits - Renamed to finalizer per answer
I am trying to do a few things in a finalizer, and the program terminates before I'm done. To simulate, I made the following test, which prints up to 20
Does this mean .NET finalizer "timeout" after 2 seconds?
~MyClass()
{
// do some cleaup
int i = 0;
while (true)
{
Console.WriteLine(i++);
Thread.Sleep(100);
}
}
For context, I have some background threads (Task objects) that's I'd like to terminate gracefully. I'm just testing to see how long it takes to do it from the finalizer.
What's a better design pattern for doing this? Perhaps have a "Shutdown" method that I have to make sure is called when closing a form? I know finalizers are meant for cleanup of unmanaged memory, but it seems nice to stop all my threads since I know it will be called.
Maybe I just let the threads terminate abruptly and not worry about it?

First, I should note that "destructors" are now more commonly referred to as "finalizers", as the former term implies these special methods work like destructors in C++, but they really don't. So you might have better luck searching if you use the newer term.
To your question, yes, there is evidence that .NET has a time limit on finalizers during shutdown - common quotes say one finalizer taking more than 2 seconds, or all finalizers taking 40 seconds - will cause the runtime to give up and just shutdown without continuing to let finalizers run.
I would recommend looking into implementing IDisposable to handle cleanup deterministically. C# has syntax sugar - the using statement - to help make this easier on the consumer's side.

Related

Revisiting Thread.Abort() - is it safe?

MSDN on migrating legacy multithreaded applications (from this page on exception handling in threads):
In general, the change will expose previously unrecognized programming problems so that they can be fixed. In some cases, however, programmers might have taken advantage of the runtime backstop, for example to terminate threads. Depending on the situation, they should consider one of the following migration strategies:
Restructure the code so the thread exits gracefully when a signal is received.
Use the Thread.Abort method to abort the thread.
If a thread must to be stopped so that process termination can proceed, make the thread a background thread so that it is automatically terminated on process exit.
In all cases, the strategy should follow the design guidelines for exceptions. See Design Guidelines for Exceptions.
This suggests that using Thread.Abort is an appropriate way to terminate a thread. Has something changed while I wasn't looking? The last I'd heard was this could cause unexpected behaviours so shouldn't be used.
Thread.Abort is a lot safer than it used to be for the following reasons.
The runtime will defer aborts while execution is in unmanaged code.
The abort will allow finally blocks to execute.
However, there is still a problem with exactly when the ThreadAbortException gets injected. Consider this code.
public class Example
{
private DateTime value = DateTime.MinValue;
public void DoSomething()
{
try
{
value = DateTime.UtcNow;
}
finally
{
}
}
}
If this code were running on a 32-bit platform the value variable could be corrupted if Thread.Abort was called and the ThreadAbortException were injected in the middle of the write to value. Since DateTime is 8 bytes the write has to take place using more than one instruction.
It is possible to guard against this by placing critical code in a finally block and by using Constrained Execution Regions, but it would be incredibly difficult to get right for all but the simplest types your define. And even then you cannot just put everything in a finally block.
Generally speaking, Thread.Abort will kill threads, leaving the data they were processing at the time in an unknown state. The state being unknown, it's usually not safe to deal with that data anymore. However, when you're trying to terminate a process, you are not expecting to deal with that thread's data anymore, so why not abort it?
Well, the problem with Thread.Abort() is that will abort the thread possibly in the middle of work. That might cause your state to be corrupted. That's why is advisable to use a volatile bool flag to control the thread, and let the thread finish its task gracefully, but based on that flag.
For more details, I recall this blog post.

What is the recommended way to guard against resource leaks in the context of ThreadAbortException?

I'm working on improving the exception-safety of a piece of code and I realized that a raised ThreadAbortException may cause undesired resource leaks, even when guarding resources with the C# using construct. For instance, consider the following code (which could be running in a separate thread).
using (TextWriter writer = CreateWriter(filename))
{
// do something with the writer.
}
TextWriter CreateWriter(string filename)
{
return new CustomWriter(File.OpenWrite(filename));
}
If the thread running this code is abnormally terminated, then I would like the file handle referenced by filename to be closed immediately. Can I do this without replacing the use of the using construct with a try/finally block?
My assumption is that ThreadAbortException may be raised at anytime, which means I should pay attention to what is happening between statements. While I can guard against the exception in CreateWriter with a try/finally block, the using construct won't do the same until after the expression in the parenthesis is evaluated, meaning the file resource is left open if the exception occurs immediately after CreateWriter returns.
I understand that a finalizer will ultimately release the file handle, but I am wondering if there is a deterministic way to address this issue without catching ThreadAbortException in each place that CreateWriter is used.
Yes, the deterministic way of preventing this is by not using Thread.Abort. Ever. Signal to your threads that is is time to stop, and let them terminate gracefully. Thread.Abort is a great big red-herring, placed in the API solely to trip you up. ;)
http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation
There is a tradeoff.
Be sure to close all resources immediately, even in the presence of ThreadAbortException
Have simpler code, but temporarily leak resources if Abort() is called
I assume that you are not calling Abort, and just want a way to be safe if someone else does. If you are calling Abort, then I'd advise that you don't. This isn't the only problem you will run into. There are other problems with Abort in the documentation.
#2 is a valid choice because callers of Abort() should expect this.
If you want to choose #1, then I don't think even a simple try/catch will help. If the ThreadAbortException can happen everywhere, then it can still happen after the file is opened (inside File.OpenWrite()) and before you can assign it to a variable that you can call Dispose() on -- you will have the same problem as using in your code.
You need semantics like
using (var handle = GetUnOpenedHandle()) {
handle.Open(); // this can't involve assignment to any field of handle
}
I'm not sure this is possible.
In many cases (but definitely not all) you could guard against a ThreadAbortException. Most of the critical code in the .NET BCL does this fairly well already. The problem is that it is really hard to get right. And for this reason most people recommend, and rightly so, to avoid aborting threads. Starting in version 2.0 the CLR made thread aborts a lot more tolerable and introduced a new set of APIs to help code authors guard against them. Take a look at Constrained Execution Regions for an in depth look at how all of this works.
I believe you are correct about your concerns with the example of the using block. For constrained execution regions to work correctly the out-of-band (asynchronous) exception must occur from within a try block. But, because of the way using expands out the expression is evaluated outside of the try block. Contrast that with the expansion of the lock block which evaluates the expression from within the try block. Well, that is true with version 4.0 of the framework anyway and that was changed specifically to guard against these exceptions.
So the question is why was the same change not made with the using block. According to Joe Duffy this was an acceptable omission because the assumption is that thread aborts should always be followed by a termination of the AppDomain which would fire off the finalizers anyway.
So yes. Your code is not tolerant of out-of-band (asynchronous) exceptions. But, the prevailing wisdom from those smarter than me is that it should not have to be.
A thread abort is most often used in the case of a fatal error, so your response should probably be to let your application terminate. If your trying to stop your own threads cleanly, use Thread.Join().

How do I terminate a worker thread when the owning object is collected?

I have an object that has a BackgroundWorker thread (purely a queue of Action delegates). i.e., it's the common, simple single-producer single-consumer scenario.
When the single producer is collected, I would like it to enqueue a Terminate action to the BackgroundWorker thread.
It almost sounds easy - use a finalizer - but that breaks the "don't touch a managed resource in a finalizer" rule.
So how do I ensure the thread terminates cleanly once it has no more work to do?
Answers I'd rather not take:
IDisposable: This would require a massive breaking change to the base class, but I accept it is perhaps required (this always seems to be a problem with the IDisposable pattern..)
ThreadPool: These are long running actions that must be run in order. So I would consider a dedicated thread to be the logical choice.
WeakReference: I just thought of this one. Perhaps it is the correct way to do this (?). Basically the Thread keeps a WeakReference back to the owning object, and periodically wakes itself to check if that WeakReference is still alive, when it dies it enqueues a Terminate. Not exactly elegant - I don't like the "periodically wakes itself" bit - but is this the best solution?
IDisposable or something similar sounds like the best approach to me - explicitly say when you've finished producing, rather than triggering that from garbage collection.
Fundamentally it sounds like the problem isn't terminating the worker thread - it's indicating that you've finished producing. I do understand that that can be tricky in some situations, but if at all possible it'll make your life more predictable if you can do that explicitly.

How do I debug a deadlock when only one thread shows up in Visual Studio?

My application is blocking indefinitely on a call to lock ( obj ), but there are no other threads in the threads window that have any code to browse at all. Isn't it kind of necessary for there to be another thread involved? Why isn't it showing up, and what could be the cause of it not showing up?
Update: I think I figured out what was causing it. I had this sort of hackish block whereby I would Wait() on a ManualResetEvent inside two locks. The problem was I needed to release those locks before Waiting so other threads could use them, so I was doing something like this:
lock ( one ) {
lock ( two ) {
...
Monitor.Exit( two );
Monitor.Exit( one );
syncEvent.Wait();
Monitor.Enter( one );
Monitor.Enter( two );
}
}
What I wasn't counting on is that Monitor.Exit() really only decrements an internal recursion counter, and it was possible the method was being called from a block that was already synchronized; thus the lock was not actually being released.
I guess it was a bad idea to begin with. I've since just moved the call to Wait() outside of the locked blocks and it seems to be working fine now.
Thanks for the insight.
Although, now that I think about it, if the method is being called from code synchronized on one of the locks, it will still not be released when the call to Wait occurs. Therefore I'll have to be careful never to call this from a synchronized block, I guess.
there are no other threads in the threads window that have any code to browse at all
I assure you that those other threads are running code. Whether you have the source code on your machine or not doesn't matter to those threads.
Isn't it kind of necessary for there to be another thread involved?
Yes.
Why isn't it showing up, and what could be the cause of it not showing up?
Perhaps the thread that took out a lock has gone to sleep. It's rude to take a lock and then sleep without unlocking it, but certainly possible. Or perhaps one of those threads that is running code that you don't have the source code to took out a lock. For example, suppose the finalizer thread took out a lock while finalizing an object, and then the finalizer thread finished its current batch of work. Again, it is rude and stupid to lock an object during finalization and then not unlock it, but it is certainly possible.
There are a million possibilities; you haven't given us nearly enough information to do anything more than guess randomly. My advice: build a small repro that clearly demonstrates the problem. In doing so you'll either figure out what the problem is yourself, or you'll have something concrete that we can discuss rather than simply making guesses in advance of facts.
A good way to debug this is to run your program through the Concurrency Profiler in Visual Studio 2010. (This is only available in higher-end SKUs, however.) It includes many tools for highlighting and investigating deadlocks, and tends to work better in many scenarios than the debugger.

Why doesn't Thread implement IDisposable?

I noticed that System.Threading.Thread implements a finalizer but not IDisposable. The recommended practice is to always implement IDisposable when a finalizer is implemented. Jeffrey Richter wrote that the guideline is "very important and should always be followed without exception".
So why doesn't Thread implement IDisposable? It seem like implementing IDisposable would be a non-breaking change that would allow deterministic cleanup of Thread's finalizable resources.
And a related question: since thread is finalizable, do I have to hold references to running Threads to prevent them from being finalized during execution?
What would disposing of a Thread object do? The "resource" in this case has its own natural clean-up - the thread finishing. Note that also the sense of ownership is missing... within the executing thread, you can always use Thread.CurrentThread, so only that thread would really able to claim any sort of ownership.
Basically I think Thread is a slightly unusual case - there's a lifetime to the underlying resource, but it isn't something that ought to be cleaned up explicitly.
That's probably because you can't dispose of a thread. Instead you can ask it to die using Abort() or alike.
This is kind of a design question, so anyone who was not involved in building this aspect of .NET can only speculate. That being said, this blog post makes a good point:
...implementing IDisposable would not make any difference, at least in the current implementation of Thread. I increased the number of threads being created and the handle count goes down at some point so there is some mechanism for closing them
Threads do naturally clean up after themselves, so they are not a resource that needs to be managed in the typical sense.

Categories

Resources