2013-03-11 4 views
4

나는 C에서 몇 가지 기능을 가지고 있으며 이것을 .net 응용 프로그램에서 사용할 것입니다. 이를 위해 C++/cli로 Wrapper 클래스를 작성했습니다.C++/cli finalizer의 무료 GCHandle에 대한 유용한 정보

에서 c 인터페이스는 콜백 함수이며 이것을 .net 대리자로 묶었습니다.

그러나 콜백 gcHandle에 대한 관리되지 않는 소스를 어떻게 릴리스해야합니까? finalizer에서 IsAllocated와 Free를 GCHandle에서 호출 할 수 있습니까? 관리되는 ressource이고 gc가 이미 그것을 릴리스 할 수 있습니까? 여기

// 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_; 
    // ... 
}; 

이 코드 안전하고이를 위해 가장 좋은 방법은 무엇인가 여기

이는 C 인터페이스를위한 코드?

미리 감사드립니다.

답변

6

대리자 개체에 추가 GCHandle 참조를 추가 할 필요가 없습니다. callbackDelegate_ 필드에 이미 참조를 올바르게 저장하고 있으므로 가비지 수집기에서 대리인이 사용 중이므로 수집해서는 안됩니다. 추가 참조가 필요하지 않습니다.

코드에서 callbackHandle_을 삭제하면됩니다.

+0

빠른 응답을 보내 주셔서 감사합니다. 추가 질문이 설정됩니다. callbackDelegate_ = nullptr; finalizer에서 안전하고 필요한가? –

+0

필드가 더 이상 사용되지 않도록 개체가 이미 참조로 남아 있지 않아서 필요하지 않습니다. 그냥 진술을 제거하십시오. –

+0

재배치는 어떻게됩니까? 이 문서에서는 https://msdn.microsoft.com/en-us/library/367eeye0.aspx (두 번째 예 참조)에서 "대리인이 재배치되지 않도록하는 GCHandle의 전역 인스턴스"가 필요하다고 말합니다. MyWrapper 클래스의 객체가 처음으로 인스턴스화 된 후에 가비지 수집기가 관리 된 위임을 재배치 할 수 있습니까? – Tarc