Is it safe to call an RCW from a finalizer?

南楼画角 提交于 2019-11-27 12:49:43
Andrew Arnott

I found out from the CLR team themselves that indeed it is not safe -- unless you allocate a GCHandle on the RCW while it's still safe to do so (when you first acquire the RCW). This ensures that the GC and finalizer haven't totaled the RCW before the managed object that needs to invoke it is finalized.

class MyManagedObject : IDisposable
{
    private ISomeObject comServer;
    private GCHandle rcwHandle;
    private IServiceProvider serviceProvider;
    private uint cookie;

    public MyManagedObject(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
        this.comServer = this. serviceProvider.GetService(/*some service*/) as ISomeObject;
        this.rcwHandle = GCHandle.Alloc(this.comServer, GCHandleType.Normal);
        this.cookie = comServer.GetCookie();
    }

    ~MyManagedObject()
    {
        this.Dispose(false);
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // dispose owned managed objects here.
        }

        if (this.rcwHandle.IsAllocated)
        {
            // calling this RCW is safe because we have a GC handle to it.
            this.comServer.ReleaseCookie(this.cookie);

            // Now release the GC handle on the RCW so it can be freed as well
            this.rcwHandle.Free();
        }
    }
}

It turns out in my particular case, my app is hosting the CLR itself. Therefore, it's calling mscoree!CoEEShutdownCOM before the finalizer thread gets to run, which kills the RCW and results in the InvalidComObjectException error I was seeing.

But in normal cases where the CLR is not hosting itself, I'm told this should work.

No it is not safe to access a RCW from the finalizer thread. Once you reach the finalizer thread you have no guarantee that the RCW is still alive. It is possible for it to be ahead of your object in the finalizer queue and hence released by the time your destructor runs on the finalizer thread.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!