C ++ / CLI:防止在非托管资源的托管的包装垃圾回收

C ++ / CLI:防止在非托管资源的托管的包装垃圾回收

问题描述:

我有一个C ++的非托管类 NativeDog 这需要从C#中使用,所以我创建一个包装类 ManagedDog

I have a C++ unmanaged class NativeDog that needs to be used from C#, so I've create a wrapper class ManagedDog.

// unmanaged C++ class
class NativeDog
{
    NativeDog(...); // constructor
    ~NativeDog(); // destructor
    ...
}

// C++/CLI wrapper class
ref class ManagedDog
{
    NativeDog* innerObject; // unmanaged, but private, won't be seen from C#
    ManagedDog(...)
    {
        innerObject = new NativeDog(...);
        ...
    }

    ~ManagedDog() // destructor (like Dispose() in C#)
    {
        // free unmanaged resources
        if (innerObject)
            delete innerObject;
    }

    !ManagedDog() // finalizer (like Finalize() in C#, in case
    {             // the user forgets to dispose)
        ~ManagedDog(); // call destructor
    }
}



一切都很好,我用类是这样的:

All is well, and I use the class like this:

// in C++/CLI
// this function is called from C++ code
void MyLibrary::FeedDogNative(NativeDog* nativedog)
{
    ... // (***)
}
// this function is called from C#, passes on the dog to the native function
void MyLibrary::FeedDogManaged(ManagedDog^ dog)
{
    NativeDog* rawdog = dog->innerObject;
    MyLibrary::FeedDogNative(rawdog);
}

// C# client code
void MyFunc()
{
    ManagedDog dog = new ManagedDog(...);
    MyLibrary.FeedDogManaged(dog);
}

请参阅什么是错的?我也没有在第一,直到很奇怪的事情开始发生不时。基本上,如果在调用后 MYFUNC()节目是由GC暂停,而它在本地函数某处 FeedDogNative (标记(***)以上),它会认为托管包装可以回收,因为它不再被使用,无论是在C#MYFUNC(这是一个局部变量,在 FeedDogManaged 调用之后将不能使用),无论是在 FeedDogManaged 。所以这实际上已经发生了多次。在GC调用终结,其中删除 S上的原生狗的对象,即使 FeedDogNative 还没有使用完!所以,我的非托管代码现在使用的是被删除的指针。

See what's wrong? I didn't either at first, until very strange things started happening from time to time. Basically if after calling MyFunc() the program is paused by the GC while it is somewhere in the native function FeedDogNative (marked (***) above), it will think the managed wrapper can be collected because it will no longer be used, neither in the C# MyFunc (it's a local variable and will not be used after the FeedDogManaged call), neither in FeedDogManaged. And so this has actually happened on occasions. The GC calls the Finalizer, which deletes the native dog object, even though FeedDogNative has not finished using it! So my unmanaged code is now using a deleted pointer.

我怎样才能避免这种情况?我能想到的一些方法(如虚拟电话冒充使用在年底 FeedDogManaged ),但会是什么推荐的方法是什么?

How can I prevent this? I can think of some ways (e.g. a dummy call pretending to use dog at the end of FeedDogManaged) but what would the recommended way be?

您需要的 GC ::的KeepAlive() FeedDogManaged $ C调用$ C>功能。好像它是一个确切的用例的。

You need a GC::KeepAlive() call in your FeedDogManaged function. Seems like it is an exact use case for that.