2012-07-02 2 views
3

관리되지 않는 라이브러리에 관리되는 함수 포인터 void (*)(void *)을 전달하려고 시도하고 있습니다. 내 관리되지 않는 라이브러리는이 콜백을 CriticalSection에 의해 보호되는 데이터 프레임에 대한 포인터로 호출합니다. 관리 콜백이 실행되는 동안 중요한 부분으로 인해 데이터 프레임을 수정할 수있는 것은 없습니다. 그러나 콜백 만 입력하면 액세스 위반 및 힙 손상이 발생합니다.관리되지 않는 콜백으로 관리되는 함수 포인터 전달

편집 : 언급하는 것을 잊었습니다. StartStreaming()은 관리하는 스레드를 훔칩니다. 게다가, 새로운 콜백에 새로운 데이터를 보내기위한 별도의 스레드를 생성합니다. 이 별도의 스레드에서 콜백이 호출됩니다.

//Start Streaming 
streaming_thread_ = gcnew Thread(gcnew ThreadStart(&Form1::WorkerThreadFunc)); 
streaming_thread_->Start(); 

: 나는 다음과했던 지금까지

extern "C" { 
#include "libavcodec\avcodec.h" 
#include "libavutil\avutil.h" 
} 

namespace TEST_OCU { 

delegate void myCallbackDelegate(void * usr_data); //Declare a delegate for my unmanaged code 

public ref class Form1 : public System::Windows::Forms::Form 
{ 
    public: 

    static void WorkerThreadFunc() 
    { 
     myCallbackDelegate^ del = gcnew myCallbackDelegate(&Form1::frame_callback); 

     MessageBox::Show("Starting to Streaming", "Streaming Info"); 
     if(rtsp_connection_ != NULL) 
      rtsp_connection_->StartStreaming(); 
      //rtsp_connection_->StartStreaming((void (*)(void *)) System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(del).ToPointer()); 
     MessageBox::Show("Done Streaming", "Streaming Info"); 
    } 

    static void __cdecl frame_callback(void * frame) 
    { 
     AVFrame * casted_frame = (AVFrame *)frame; 
    } 

private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) 
    { 
     if(rtsp_connection_ == NULL) 
      rtsp_connection_ = new NeyaSystems::RTSPConnection("rtsp://url"); 
    } 

    private: static RTSPConnection * rtsp_connection_ = NULL; 
} 
} 
  • 내가 무의미 코드를 많이 생략 한을 ...에 NULL에
  • StartStreaming 기본값 포인터,이 경우에는 부패가 발생하지 않습니다.
  • StartStreaming delegat 에드 함수 포인터는
  • RTSPConnection 네이티브 C로 구현 힙 손상이 발생 ++와 C가 (위해 libavcodec)
  • RTSPConnection는 두 개의 스레드, 통신 및 프레임 파견 스레드를 포함뿐만 아니라 호출 포함 (호출 관리 콜백)

수 아무도 나에게 빵 부스러기를주지 않습니까? 미리 감사드립니다.

답변

4

EDIT : 크로스 스레드 호출에 문제가 없습니다. 관리되지 않는 호출자가 __cdecl 함수를 호출하려면 UnmanagedFunctionPointerAttribute 특성을 사용하여 대리자 형식을 데코레이션해야합니다. 당신의 방법에서 지역 변수로 대리자를 선언

using namespace System::Runtime::InteropServices; 

[UnmanagedFunctionPointerAttribute(CallingConvention::Cdecl)] 
delegate void myCallbackDelegate(void * usr_data); 
+0

안녕하세요, 먼로, WorkerThreadFunc를 의미합니까? 내 진짜 호출에서, 나는 frame_callback에서 GUI 호출을하고 Form :: Update() delegate에서'BeginInvoke'를 사용합니다. – Constantin

+0

@ Constantin BeginInvoke를 수행하는 가장 좋은 장소는 Form 인스턴스 자체에있을 것임을 경험을 통해 알았습니다 ... 호출 스레드가 UI 스레드인지 여부를 아는 가장 좋은 컨텍스트를가집니다. –

+0

아, 이제는 frame_callback에서 UI 함수를 호출하지 않는다는 것을 알았습니다. 내 잘못이야. 아마도 __cdecl 제거? –

2
myCallbackDelegate^ del = gcnew myCallbackDelegate(&Form1::frame_callback); 

. 로컬 변수는 로컬 변수를 사용하는 마지막 명령 바로 다음에서 가비지 수집 대상이됩니다. Marshal :: GetFunctionPointerForDelegate()를 올바르게 사용하고 있지만 가비지 컬렉터가 대리자가 사용 중임을 인식하는 데 충분하지 않습니다. 네이티브 코드에서 참조를 추적 할 수 없습니다. 따라서 StartStreaming() 호출 중 또는 이후에 발생하는 다음 가비지 수집은 대리자를 파괴합니다. 그리고 콜백은 폭탄을 터뜨릴 것입니다.

정확히 콜백이 중지되는 시점은 명확하지 않습니다. 적어도 GC :: KeepAlive (del); StartStreaming() 호출 후. 메서드 호출에서 "Start"를 고려하여 WorkerThreadFunc()가 실행을 멈춘 후에 콜백이 수행되면 폼 클래스의 필드로 저장하여 델리게이트 객체를 오래 유지해야합니다. 프로그램이 종료 될 때까지이를 유지하기 위해 static으로 선언 할 수 있습니다.

+0

안녕하세요 한스, StartStreaming() 호출이 차단되었습니다 ... 내가 사용하는 라이브러리 때문에 (나는 그것을 싫어하지만 그 문제에 대해 말을하지 않습니다.) StartStreaming 호출 전에 계속 KeepAlive 호출을 포함해야합니까? – Constantin

+0

그런 다음 StartStreaming이 실행되는 동안 대리자 개체를 활성 상태로 유지하려면 GC :: KeepAlive() 호출이 필요합니다. –

+0

위대한, 감사합니다 한스! – Constantin

관련 문제