Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AppDomain.Unload throws in Finalizer?

So here is the story so far, I have this worker thingy which uses an AppDomain to perform some task. The domain is expensive to setup and teardown. So I create a cache per-thread of WeakReference objects to the worker thingy like so:

class Worker
{
    [ThreadStatic]
    static Dictionary<string, WeakReference> _workers;

    public static Worker Fetch( ... ) { you get the idea }

    private AppDomain _domain;
    public Worker(...)
    {
        _domain = AppDomain.Create( ... );
    }

    ~Worker()
    { 
        AppDomain.Unload(_domain);
    }

    // bla bla bla
}

The problem I'm having is that seems to always throw an exception in the call to AppDomain.Unload when GC collects:

System.CannotUnloadAppDomainException: Error while unloading appdomain. (Exception from HRESULT: 0x80131015)"

So I'm thinking that's wierd, I know I don't have anything 'running' in that domain... Whats the deal? A bit of digging and trial and error I came up with this:

    ~Worker()
    { 
        new Action<AppDomain>(AppDomain.Unload)
            .BeginInvoke(_domain, null, null);
    }

So my Questions are:

  1. Will AppDomain.Unload always fail from a Finalizer? Why?
  2. Am I going to experience anything 'undesirable' with the above workaround?
like image 391
csharptest.net Avatar asked Oct 31 '10 19:10

csharptest.net


1 Answers

AppDomains are unloaded by a separate CLR thread. That thread cannot run while the finalizer thread is running. You're getting the exception because the CLR notices that the unload thread isn't making progress. It never gets going because the finalizer thread is blocked on the Unload call.

Deadlock.

Your workaround indeed solves that deadlock. Doing the unloading explicitly instead of relying on a finalizer is the better approach here.

like image 84
Hans Passant Avatar answered Sep 28 '22 07:09

Hans Passant