views:

18

answers:

2

I've got a problem problem with threading and disposing resources.

I've got a C# Windows Forms application which runs expensive operation in a thread. This thread instantiates an ActiveX control (AxControl). This control must be disposed as it uses a high amount of memory. So I implemented a Dispose() method and even a destructor.

After the thread ends the destructor is called. This is sadly called by the UI thread. So invoking activexControl.Dispose(); fails with the message "COM object that has been separated from its underlying RCW", as the object belongs to another thread.

How to do this correctly or is it just a bad design I use?

(I stripped the code down to the minimum including removing any safety concerns.)

class Program
{
    [STAThread]
    static void Main()
    {
        // do stuff here, e.g. open a form

        new Thread(new ThreadStart(RunStuff);

        // do more stuff
    }

    private void RunStuff()
    {
        DoStuff stuff = new DoStuff();
        stuff.PerformStuff();
    }
}

class DoStuff : IDisposable
{
    private AxControl activexControl;

    DoStuff()
    {
        activexControl = new AxControl();
        activexControl.CreateControl(); // force instance
    }

    ~DoStuff()
    {
        Dispose();
    }

    public void Dispose()
    {
        activexControl.Dispose();
    }

    public void PerformStuff()
    {
        // invent perpetuum mobile here, takes time
    }
}
A: 

Why don't you have the worker thread dispose of it explicitly?

You could possible change the

DoStuff stuff = new DoStuff();
stuff.PerformStuff();

To a

using(DoStuff stuff = new DoStuff())
{
     stuff.PerformStuff();
}

So you don't even have to worry about it.

ho1
A: 

I'm not clear what you mean by an ActiveX Control that implements a Dispose method. The IDisposable pattern is intended for managed code. To release a COM object, you would normally use Marshal.ReleaseComObject - perhaps you're doing that inside your AxControl class, whose implementation you don't show.

A couple of things wrong with the above code.

You should be disposing the IDisposable DoStuff instance:

private void RunStuff() 
{ 
    using (DoStuff stuff = new DoStuff())
    {
        stuff.PerformStuff(); 
    }
} 

You should not be accessing managed resources in a finalizer - in your case the finalizer calls Dispose which then references the managed axControl instance. This instance may have already been collected by the time your finalizer runs.

Since you are not using unmanaged resources directly in the DoStuff class, you probably don't need a finalizer, but if you do have one, follow the standard IDisposable pattern on MSDN, and don't attempt to dispose any managed objects.

UPDATE

Comment:

The AxControl is the .NET Interop Wrapper DLL which is generated by Visual Studio.

In this case, what is the Dispose() method? I don't see why you would implement such a method in an ActiveX control, which has deterministic finalization - normally you'd do your cleanup when the last COM reference is released.

Your DoStuff.Dispose method might want to release the COM object, e.g.

public void Dispose()  
{  
    activexControl.Dispose();  
    Marshal.ReleaseComObject(activexControl);
}
Joe
The AxControl is the .NET Interop Wrapper DLL which is generated by Visual Studio. And there each ActiveX control is derived from the .NET control. (Surely to be able to place it onto a Windows Form).
Stefan Teitge