C# 在线程之间的Invoke()上检测到CallbackOnCollectedDelegate
我读过类似问题的解决方案,但在我的案例中,我很难让它们发挥作用。我在Visual Studio 2010中运行的C#.NET 4.0项目中遇到以下错误: 检测到CallbackOnCollectedDelegate消息:已进行回调 在类型为的垃圾收集委托上 “测试!VLCMTest.Data+VCECLB_GrabFrame_CallbackEx::Invoke'。今年五月 导致应用程序崩溃、损坏和数据丢失。路过时 委托给非托管代码时,托管 应用程序,直到保证永远不会调用它们为止 以下是我的情况:我有一个后台线程,在收集数据帧时会收到通知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'。今年五月 导致应用程序崩溃、损坏和数据丢失。路过时 委托给非托管代码时,托管 应用程序,直到保证永远不会调用它们为止 以下是我的情况
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()方法中的回调变量是一个局部变量。不足以使委托对象保持活动状态。就是这样!我首先构建了包含背景线程的部分,它似乎可以工作。然后我添加了将事件发送到主线程的部分,这就是我看到问题的时候。我一直在看主线程代码,而不是询问后台线程。谢谢你的帮助。如果你想发表你的评论作为回答,我很乐意接受。