我已经阅读过类似问题的解决方案,但是我无法让他们在我的案例中工作。我在Visual Studio 2010中运行的C#.NET 4.0项目中收到以下错误:
检测到CallbackOnCollectedDelegate消息:进行了回调 在垃圾收集的类型委托上 'VLCMTest!VLCMTest.Data + VCECLB_GrabFrame_CallbackEx ::调用'。这可能 导致应用程序崩溃,损坏和数据丢失。路过时 委托非托管代码,他们必须由托管保持活着 应用程序,直到确保它们永远不会被调用。
以下是我的情况:我有一个后台线程,在收集数据帧时会收到通知。
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();
答案 0 :(得分:1)
正如Hans Passant所说,问题在于Start()方法中的回调变量。我将其更改为以下内容:
private GrabFrame_CallbackEx callback;
public void Start()
{
// Start grabbing frames
isGrabRunning = true;
callback = new GrabFrame_CallbackEx(GrabCallback);
StartGrabEx(callback);
}
现在一切正常!