|
|
Finalization aborted when taking locks inside finalizers |
|
Author |
Message |
Alois

|
Posted: Common Language Runtime, Finalization aborted when taking locks inside finalizers |
Top |
Hi,
its me and my finalizers again. In my quest to get rock solid and predictable shutdown behaviour I stumbled accross the bizarre phenomen that when I take locks inside a finalizer the whole finalization stuff during shutdown is cancelled. Is this the expected behaviour or did I miss something
using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Runtime.ConstrainedExecution;
namespace LocksInsideFinalizers { class Other : CriticalFinalizerObject { ~Other() { Console.WriteLine("~Other called"); } }
class Program { string myName; public Program(string name) { myName = name; Thread t = new Thread(ThreadFunc); t.IsBackground = true; t.Name = "Tester Thread"; t.Start();
Thread.Sleep(500); }
void ThreadFunc() { try { lock (this) { while (true) { Console.WriteLine("ThreadFunc active " + myName); Thread.Sleep(1000); } } } catch (Exception ex) { Console.WriteLine("ThreadFunc Excecption caught: {0}", ex); } finally { Console.WriteLine("ThreadFunc does exit now"); } }
object myLock = new object(); ~Program() { Console.WriteLine("~Program called"); try { lock (this) { Console.WriteLine("~Program lock taken"); } } finally { Console.WriteLine("~Program exit"); } }
static void Main(string[] args) { Program p1 = new Program("1"); Program p2 = new Program("2");
Other o1 = new Other(); Other o2 = new Other();
} } }
Depending on what I run I get C:\Source\LocksInsideFinalizers\LocksInsideFinalizers\bin\Debug>LocksInsideFinalizers.exe ThreadFunc active 1 ThreadFunc active 2 ThreadFunc active 1 ~Other called ~Other called ~Program called
But when I lock on the myObject inside ~Program which is not owned by another thread I get: ThreadFunc active 1 ThreadFunc active 2 ThreadFunc active 1 ~Other called ~Other called ~Program called ~Program lock taken ~Program exit ~Program called ~Program lock taken ~Program exit
Does the whole finalization stuff blow up during shutdown if only one finalizer ever tries to aquire a lock which another thread already owns Even the Critical Finalizer are not run when such an event does occur.
Yours, Alois Kraus
.NET Development37
|
|
|
|
 |
nobugz

|
Posted: Common Language Runtime, Finalization aborted when taking locks inside finalizers |
Top |
Apparently. Perhaps an unreasonable response to an unreasonable request. There is no need to do any locking whatsoever. Finalizers run on the finalization thread and it is guaranteed that no other thread can have a reference to the object. Even the myLock reference is unsafe, it might already have been finalized...
|
|
|
|
 |
Alois

|
Posted: Common Language Runtime, Finalization aborted when taking locks inside finalizers |
Top |
When your finalizer is called the full object graph is still there. Your member variables will not be null when your finalizer is called (except if you got an exception during the cctor, ctor of your object where you see a partially constructed type). Locking on an object during finalization is possible but I want to understand what implications the shutdown behaviour has on my freedom to write code in my finalizers. This includes locking on objects from another thread. Windows forms applications do seem to behave differently.
What happens during shutdown can be read here:
http://geekswithblogs.net/akraus1/archive/2006/10/30/95435.aspx
Yours,
Alois Kraus
|
|
|
|
 |
Lepaca

|
Posted: Common Language Runtime, Finalization aborted when taking locks inside finalizers |
Top |
I don't understand...
do you serch a memory leak with a concurrent lock
|
|
|
|
 |
Alois

|
Posted: Common Language Runtime, Finalization aborted when taking locks inside finalizers |
Top |
I want to get a feeling what programming constructs are allowed inside a finalizer that does
a) behave correctly during application run time
b) is executed during shutdown with the other finalizers and does not cause the CLR to abort finalization because I do something illegal.
The main question is: Is it allowed to take locks inside a finalizer or not If no what will happen during shutdown
Yours,
Alois Kraus
|
|
|
|
 |
Joe Duffy

|
Posted: Common Language Runtime, Finalization aborted when taking locks inside finalizers |
Top |
I recently wrote a blog entry that should answer your question: http://www.bluebytesoftware.com/blog/PermaLink,guid,c3993fa3-4d71-414c-bfa3-bca600869018.aspx.
Here's a relevant quote:
If a lock was orphaned in the process of stopping all running threads, the shutdown code path will fail to acquire the lock. If such acquisitions are done with non-timeout (or long timeout) acquires, a hang will ensue. To cope with this (and any other sort of hang that might happen), the CLR annoints a watchdog thread to keep an eye on the finalizer thread. Although configurable, by default the CLR will let finalizers run for 2 seconds before becoming impatient; if this timeout is exceeded, the finalizer thread is stopped, and shutdown continues without draining the rest of the finalizer queue.
Regards,
--joe
|
|
|
|
 |
Alois

|
Posted: Common Language Runtime, Finalization aborted when taking locks inside finalizers |
Top |
Hi Joe,
thanks for pointing me to the answer I was seeking for. I am a regular reader of your blog but there is so much good content on it that I did miss this paragraph so far ;-). This means that it might be ok to take looks inside a finalizer if you want to "Dispose" only at run time and do not care what happens at shutdown. But if you care that the shutdown does not end up in unhandled exceptions/ rude aborts, ... you should avoid locks at all costs inside your finalizaiton logic. I did already take a deep look at the (not so many as one could expect) BCL finalizers where I did never find a lock in the finalization path.
Yours, Alois Kraus
|
|
|
|
 |
Alois

|
Posted: Common Language Runtime, Finalization aborted when taking locks inside finalizers |
Top |
Hi Joe,
you did mention that the timeout value is configurable. So far I have not found a App.Config value that allows me to do this. Is this a registry key
Yours, Alois Kraus
|
|
|
|
 |
|
|