强制GC使用另一个线程上下文

时间:2012-12-05 09:57:45

标签: c# multithreading garbage-collection thread-safety idisposable

我正在使用OpenGL,并且需要手动处理非托管对象。 (特别是纹理和顶点缓冲区)。

问题是,必须从主线程(唯一可以创建或销毁此类对象的线程)中调用释放顶点缓冲区的函数

我已经正确地为我的托管对象实现了IDisposable和析构函数。 垃圾收集器也正确调用函数。 但所有这一切都将失败,因为垃圾收集器在不同的线程上运行,当GC调用freeing-functions(DeleteBuffers(...),DeleteTexture(...)等)时,它会崩溃。

所以我想出了两个想法来解决这个问题:

  1. 将必须释放的对象添加到列表中,然后在主线程中检查该列表。 问题:需要我想避免的同步/锁定。 也许使用BlockingCollection<>

  2. 以某种方式强制GC使用主线程来完成它的工作。

  3. 有什么方法我不知道这样做吗? 我该如何正确处理这些物体? 我必须自己清理吗? (意思是我停止使用析构函数并且总是自己释放对象?)

2 个答案:

答案 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

     

禁用垃圾收集并发并回收一个对象   批量通话。这是最具侵入性的模式。此模式专为   以响应性为代价的最大吞吐量。