C# 在线程之间的Invoke()上检测到CallbackOnCollectedDelegate

C# 在线程之间的Invoke()上检测到CallbackOnCollectedDelegate,c#,multithreading,delegates,invoke,C#,Multithreading,Delegates,Invoke,我读过类似问题的解决方案,但在我的案例中,我很难让它们发挥作用。我在Visual Studio 2010中运行的C#.NET 4.0项目中遇到以下错误: 检测到CallbackOnCollectedDelegate消息:已进行回调 在类型为的垃圾收集委托上 “测试!VLCMTest.Data+VCECLB_GrabFrame_CallbackEx::Invoke'。今年五月 导致应用程序崩溃、损坏和数据丢失。路过时 委托给非托管代码时,托管 应用程序,直到保证永远不会调用它们为止 以下是我的情况

我读过类似问题的解决方案,但在我的案例中,我很难让它们发挥作用。我在Visual Studio 2010中运行的C#.NET 4.0项目中遇到以下错误:

检测到CallbackOnCollectedDelegate消息:已进行回调 在类型为的垃圾收集委托上 “测试!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));
            }
        }
    }
然后,我开始数据收集:

    public void Start()
    {

        // Start grabbing frames
        isGrabRunning = true;
        GrabFrame_CallbackEx callback = new GrabFrame_CallbackEx(GrabCallback);
        StartGrabEx(callback);
    }
GrabCallback函数如下所示:

    // 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);
    }
    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();

正如Hans Passant所说,问题在于Start()方法中的回调变量。我将其更改为以下内容:

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

public void Start()
{

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

一切都好了

该错误位于导致FrameGrapped()方法运行的代码中。你没有发。将委托对象存储在静态变量中,这样就永远不会对其进行垃圾收集。您需要做的不仅仅是确保委托是静态变量。很难告诉您需要在何处更改代码,因为您没有提供导致FrameGrabber()方法运行的代码(或者它作为委托传递给某个对象,或者某个对象作为委托传递给本机frame grabber库),如果没有该代码,我们无法告诉您任何过于具体的内容。对此表示抱歉。我试图只使用相关的代码(太多的代码是其他问题中常见的抱怨),但看起来我遗漏了一些重要的东西。我将编辑我的问题。是的,Start()方法中的回调变量是一个局部变量。不足以使委托对象保持活动状态。就是这样!我首先构建了包含背景线程的部分,它似乎可以工作。然后我添加了将事件发送到主线程的部分,这就是我看到问题的时候。我一直在看主线程代码,而不是询问后台线程。谢谢你的帮助。如果你想发表你的评论作为回答,我很乐意接受。