1

同様の問題の解決策を読みましたが、私の場合、それらを機能させるのに問題があります。Visual Studio 2010で実行されているC#.NET4.0プロジェクトで次のエラーが発生します。

CallbackOnCollectedDelegateが検出されましたメッセージ:タイプ'VLCMTest!VLCMTest.Data + VCECLB_GrabFrame_CallbackEx::Invoke'のガベージコレクションされたデリゲートでコールバックが行われました。これにより、アプリケーションのクラッシュ、破損、データの損失が発生する可能性があります。デリゲートをアンマネージコードに渡す場合、デリゲートが呼び出されないことが保証されるまで、デリゲートはマネージアプリケーションによって存続する必要があります。

これが私の状況です。データのフレームが収集されたときに通知されるバックグラウンドスレッドがあります。

protected AutoResetEvent frameGrabbed;
public event EventHandler<DataFrameInfo> FrameGrabbedEvent;

    private void DataCollectionThread()
    {
        while (true)
        {
            frameGrabbed.WaitOne();

            lock (locker)
            {
                FrameGrabbedEvent(this, new DataFrameInfo(lastFrame.BufferIndex, lastFrame.FrameNumber, lastFrame.FrameTimestamp));
            }
        }
    }

DataFrameInfoクラスは、フレームに関するいくつかの情報(フレームバッファーへのインデックス、フレーム番号、およびタイムスタンプ)を格納します。このクラスのインスタンスを作成し、それをメインスレッドに渡して、データを表示できるようにします。メインスレッドのコードは次のようになります。

    // Delegate for the Invoke call, 
    // make it static to prevent a problem with garbage collection
    delegate void GetFrameDelegate(DataFrameInfo frameInfo);
    private static GetFrameDelegate d;

    /// <summary>
    /// Did we just receive a frame?
    /// </summary>
    /// <param name="source"></param>
    /// <param name="args"></param>
    void frameGrabbed(object source, DataFrameInfo args)
    {
        if (this.InvokeRequired)
        {
            // It's on a different thread, so use Invoke.
            d = new GetFrameDelegate(GetFrame);
            this.Invoke(d, new object[] { args });
            return;
        }

        // Get the Frame
        GetFrame(args);
    }

    private void GetFrame(DataFrameInfo frameInfo)
    {
        // Call Display Frame
        Debug.WriteLine("Frame: The bufferIndex is " + frameInfo.BufferIndex);
        Debug.WriteLine("Frame: The number is " + frameInfo.FrameNumber);
        Debug.WriteLine("Frame: The timestamp is " + frameInfo.FrameTimestamp / 1000);
    }

FrameGrabbedEventは、frameGrabbed()関数に接続されています。frameGrabbed()は別のスレッドから呼び出されているため、Invokeが必要です。それでは、今のところ、データの表示に取り組む前に、フレームの詳細をダンプしようとしています。

興味深いことに、プログラムはしばらくの間正常に実行されます。プログラムのメインウィンドウをデスクトップ上で動かすとすぐに、エラーがほぼ瞬時に表示されます。オブジェクトが使用される前にガベージコレクションが行われるように、タイミングを変更する必要があります。最も提案された解決策は、デリゲートを静的にすることであるように見えましたが、それは私にとってはうまくいきません。

アップデート

関連するコードを見逃したようです。以下は、frameGrabbedイベントを引き起こすコードです。基本的に、これは私が使用しているDLLによって呼び出される割り込みハンドラーです。

私は次のことを宣言します。

// Function pointer used by StartGrabEx
public delegate void GrabFrame_CallbackEx(IntPtr userData, ref FrameInfoEx frameInfo);

次に、次のコマンドでデータ収集を開始します。

    public void Start()
    {

        // Start grabbing frames
        isGrabRunning = true;
        GrabFrame_CallbackEx callback = new GrabFrame_CallbackEx(GrabCallback);
        StartGrabEx(callback);
    }

GrabCallback関数は次のようになります。

    FrameInfo lastFrame;

    private void GrabCallback(IntPtr userData, ref FrameInfoEx frameInfo)
    {
        // Are we grabbing frames?
        if (!isGrabRunning)
        {
            return;
        }

        lock (locker)
        {
            lastFrame = new DataFrameInfo(bufferIndex, frameInfo.number, frameInfo.timestamp);
        }

        // We've captured a frame, notify the DataCollectionThread
        frameGrabbed.Set();
    }

この更新を見ると、おそらく問題はlastFrameにありますが、GrabCallbackでlastFrameを更新するようにコードを変更したと思いましたが(newを使用するのではなく)、それでも失敗しました。

アップデート#2

おそらく、DataCollectionThreadがそのように宣言されていることにも言及する必要があります。

DataCollectionThread = new Thread(DataCollectionThread );
DataCollectionThread .Name = "DataCollectionThread ";
DataCollectionThread .IsBackground = true;
DataCollectionThread .Start();
4

1 に答える 1

2

Hans Passantが言ったように、問題はStart()メソッドのコールバック変数にありました。私はそれを次のように変更しました:

private GrabFrame_CallbackEx callback;

public void Start()
{

    // Start grabbing frames
    isGrabRunning = true;
    callback = new GrabFrame_CallbackEx(GrabCallback);
    StartGrabEx(callback);
}

すべてが機能しています!

于 2012-10-26T01:44:46.103 に答える