4

私はcにいくつかの関数を持っており、これを.netアプリケーションで使用します。このために、C ++/cliを使用してWrapperクラスを作成しました。

cインターフェースにはコールバック関数があり、これを.netデリゲートでラップします。

しかし、コールバックgcHandleのアンマネージリソースをどのように解放する必要がありますか?ファイナライザーでIsAllocatedとFreeをGCHandleから呼び出すことは許可されていますか?それは管理されたリソースであり、gcがすでにそれをリリースしている可能性があるためですか?

cインターフェースのコードは次のとおりです。

// C functions

#ifdef __cplusplus
extern "C" {
#endif

    typedef void (*my_native_callback)(const uint8_t buffer[], uint32_t buffer_len);

    void register_callback(my_native_callback c, uint32_t* id);

    void remove_callback(uint32_t id);

#ifdef __cplusplus
}
#endif

そしてここに.netラッパー:

// .net wrapper (c++/cli)
public ref class MyWrapper
{
public:
    MyWrapper()
    {
        RegisterCallback();
    }

    // Destructor.
    ~MyWrapper()
    {
        this->!MyWrapper();
    }

protected:
    // Finalizer.
    !MyWrapper()
    {
        RemoveCallback();       // <- Is this safe?
        // ... release other unmanaged ressorces
    }

private:
    void RegisterCallback()
    {
        uint32_t id = 0;
        callbackDelegate_ = gcnew MyCallbackDelegate(this, &MyWrapper::OnCallback);
        callbackHandle_ = System::Runtime::InteropServices::GCHandle::Alloc(callbackDelegate_);
        System::IntPtr delegatePointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(callbackDelegate_);
        register_callback(static_cast<my_native_callback>(delegatePointer.ToPointer()), &id);
        callbackId_ = id;
    }

    void RemoveCallback()
    {
        if (callbackId_)
        {
            remove_callback(callbackId_);
            callbackId_ = 0;
        }
        if (callbackHandle_.IsAllocated)        // It this safe in the finalizer?
        {
            callbackHandle_.Free();             // It this safe in the finalizer?
        }
        callbackDelegate_ = nullptr;            // It this safe in the finalizer?
    }


    void OnCallback(const uint8_t* buffer, uint32_t buffer_len)
    {
        // ...
    }

private:
    [System::Runtime::InteropServices::UnmanagedFunctionPointer(System::Runtime::InteropServices::CallingConvention::Cdecl)]
    delegate void MyCallbackDelegate(const uint8_t* buffer, uint32_t buffer_len);   
    MyCallbackDelegate^ callbackDelegate_;
    System::Runtime::InteropServices::GCHandle callbackHandle_;
    int callbackId_;
    // ... 
};

コードスニペットは安全ですか?これのベストプラクティスは何ですか?

前もって感謝します。

4

1 に答える 1

6

デリゲートオブジェクトにGCHandle参照を追加する必要はありません。ガベージコレクターにデリゲートが使用中であり、収集されるべきではないことを納得させるのに十分な、callbackDelegate_フィールドに既に正しく参照が格納されています。追加の参照は必要ありません。

コードからcallbackHandle_を削除するだけです。

于 2013-03-11T14:05:39.550 に答える