通过托管函数指针作为非托管回调(Pass Managed Function Pointer As U

2019-06-26 00:08发布

我试图托管函数指针传递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默认为一个空指针,在这种情况下,我没有得到任何腐败
  • StartStreaming与委托函数指针导致堆损坏
  • RTSPConnection在本地C ++实现,包含C调用以及(libavcodec的)
  • RTSPConnection包含两个线程,通信和帧调度线程(调用管理回调)

谁能给我一个面包屑? 非常感谢你提前。

Answer 1:

编辑:不是一个跨线程调用问题。 如果托管调用方希望调用__cdecl功能,那么你必须装饰与UnmanagedFunctionPointerAttribute属性的委托类型。

using namespace System::Runtime::InteropServices;

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


Answer 2:

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

声明委托在你的方法的局部变量。 局部变量使用它们的最后一条语句之后都受到垃圾收集。 您正确使用元帅:GetFunctionPointerForDelegate(),但是这还不足以使垃圾收集明白委托是在使用中,它无法跟踪在本机代码的引用。 所以接下来的垃圾收集过程中或StartStreaming()调用后发生将会摧毁委托。 和你的回调将炸弹。

目前还不清楚停止正在进行回调什么时候。 至少,你需要把GC ::保持活动(DEL); 后StartStreaming()调用。 如果回调的WorkerThreadFunc后作出()停止运行,可能考虑到“开始”的方法调用,您必须活得更长的保持委托对象,比方说,把它作为你的窗体类的字段。 可能的声明为静态的,以保持它活着,直到程序终止。



文章来源: Pass Managed Function Pointer As Unmanaged Callback