4

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委任された関数ポインタを使用すると、ヒープが破損します
  • RTSPConnectionネイティブC++で実装され、C呼び出しも含まれています(libavcodec)
  • RTSPConnection通信とフレームディスパッチスレッドの2つのスレッドが含まれています(マネージドコールバックを呼び出します)

誰かが私にパンくずをくれませんか?よろしくお願いします。

4

2 に答える 2

4

編集:クロススレッド呼び出しでは問題ありません。アンマネージ呼び出し元が__cdecl関数を呼び出すことを期待している場合は、デリゲート型をUnmanagedFunctionPointerAttribute属性で修飾する必要があります。

using namespace System::Runtime::InteropServices;

[UnmanagedFunctionPointerAttribute(CallingConvention::Cdecl)] 
delegate void myCallbackDelegate(void * usr_data); 
于 2012-07-02T17:27:40.320 に答える
3
 myCallbackDelegate^ del = gcnew myCallbackDelegate(&Form1::frame_callback);

これにより、デリゲートがメソッド内のローカル変数として宣言されます。ローカル変数は、それらを使用する最後のステートメントの直後にガベージコレクションの対象になります。Marshal :: GetFunctionPointerForDelegate()を正しく使用していますが、ガベージコレクターにデリゲートが使用中であることを認識させるには不十分であり、ネイティブコードの参照を追跡できません。したがって、StartStreaming()呼び出し中または呼び出し後に行われる次のガベージコレクションは、デリゲートを破棄します。そして、あなたのコールバックは爆撃します。

コールバックがいつ停止するかは正確にはわかりません。少なくとも、GC :: KeepAlive(del);を配置する必要があります。StartStreaming()呼び出しの後。おそらくメソッド呼び出しの「Start」を考慮して、WorkerThreadFunc()の実行が停止した後にコールバックが行われる場合は、たとえばフォームクラスにフィールドとして格納することにより、デリゲートオブジェクトをより長く存続させる必要があります。プログラムが終了するまで存続させるために静的と宣言される可能性があります。

于 2012-07-02T17:54:40.030 に答える