我正在使用OpenGL,并且需要手动处理非托管对象。 (特别是纹理和顶点缓冲区)。
问题是,必须从主线程(唯一可以创建或销毁此类对象的线程)中调用释放顶点缓冲区的函数。
我已经正确地为我的托管对象实现了IDisposable和析构函数。 垃圾收集器也正确调用函数。 但所有这一切都将失败,因为垃圾收集器在不同的线程上运行,当GC调用freeing-functions(DeleteBuffers(...),DeleteTexture(...)等)时,它会崩溃。
所以我想出了两个想法来解决这个问题:
将必须释放的对象添加到列表中,然后在主线程中检查该列表。 问题:需要我想避免的同步/锁定。 也许使用BlockingCollection<>
以某种方式强制GC使用主线程来完成它的工作。
有什么方法我不知道这样做吗? 我该如何正确处理这些物体? 我必须自己清理吗? (意思是我停止使用析构函数并且总是自己释放对象?)
答案 0 :(得分:1)
这个想法很简单你有一个队列(使用ConcurentQueue来保证线程安全) 让你的finlizers填充这个队列,你的主循环清空它。
试试这个链接: http://www.opentk.com/node/101
A user of the Tao Framework implemented this idea with promising results. He wrote wrappers for OpenGL resources and implemented the disposable pattern like this:
private void Dispose(bool manual)
{
if (!disposed)
{
if (manual)
{
Gl.glDeleteTextures(1, ref _tid);
GC.SuppressFinalize(this);
disposed = true;
}
else
{
GC.KeepAlive(SimpleOpenGlControl.DisposingQueue);
SimpleOpenGlControl.DisposingQueue.Enqueue(this);
}
}
}
SimpleOpenGlControl.DisposingQueue是一个包含对OpenGL资源的引用的队列。在程序执行期间定期访问它,处理其中包含的数据。请注意“其他”'除非您实际忘记释放资源,否则永远不会执行子句。这是两全其美的:您可以手动释放资源(没有性能损失),但是如果您忘记了某些事情,垃圾收集器仍会在您之后清理。更好的是,实现很简单! 现在,我们只需要了解如何处理多个OpenGL上下文。
答案 1 :(得分:0)
你试过了吗?
GCSettings.LatencyMode = GCLatencyMode.Batch;
这应该会阻止GC在其他线程上运行。
MSDN
禁用垃圾收集并发并回收一个对象 批量通话。这是最具侵入性的模式。此模式专为 以响应性为代价的最大吞吐量。