我已经阅读了类似问题的解决方案,但我无法让它们在我的情况下工作。在 Visual Studio 2010 中运行的 C# .NET 4.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();