2012-07-02 113 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; 
} 
} 
  • 我省略了很多無謂的代碼...
  • StartStreaming默認爲NULL指針,在這種情況下,我沒有損壞
  • StartStreaming與委託ED函數指針導致堆損壞
  • RTSPConnection在本地C++實現和含有C呼叫以及(libavcodec的)
  • RTSPConnection包含兩個線程,通信和幀調度線程(調用管理回調)
莫非

有人給我一個麪包屑?提前謝謝你。

回答

4

編輯:不是跨線程調用的問題。如果非託管調用方期望調用__cdecl函數,則必須使用UnmanagedFunctionPointerAttribute特性修飾委託類型。

using namespace System::Runtime::InteropServices; 

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

嘿夢露,你的意思是WorkerThreadFunc?在我真正的電話中,我在我的frame_callback中有GUI調用,並且我在'Form :: Update()'委託上使用'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()調用之後。如果在WorkerThreadFunc()停止運行後進行回調,可能考慮到方法調用中的「開始」,則必須通過將其保存爲表單類中的字段來延長活動時間。可能聲明的靜態直到程序終止才能保持活動狀態。

+0

嗨漢斯,StartStreaming()調用阻塞...由於我使用的庫(我討厭它,但我沒有發言權)。我應該在StartStreaming調用之前還包含KeepAlive調用嗎? – Constantin

+0

然後,您需要GC :: KeepAlive()調用,以便在StartStreaming正在運行時保持委託對象處於活動狀態。 –

+0

太好了,謝謝你Hans! – Constantin

相關問題