【问题标题】:Force GC to use another thread-context强制 GC 使用另一个线程上下文
【发布时间】:2012-12-05 18:14:07
【问题描述】:

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

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

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

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

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

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

有没有我不知道的方法可以做到这一点? 我应该如何正确处理这些对象? 我必须自己清理吗? (意思是我停止使用析构函数并总是自己释放对象?)

【问题讨论】:

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


    【解决方案1】:

    这个想法很简单,你有一个队列(使用 ConcurentQueue 来保证线程安全) 让你的 finlizer 填满这个队列,然后你的主循环清空它。

    试试这个链接: 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 资源的引用的队列。在程序执行期间定期访问它,处理其中包含的数据。注意'else' 子句永远不会被执行,除非你真的忘记释放资源。这是两全其美的:您可以手动释放资源(不会影响性能),但如果您忘记了什么,垃圾收集器仍会在您之后清理。更好的是,实现非常简单! 现在,我们只需要了解如何处理多个 OpenGL 上下文。

    【讨论】:

      【解决方案2】:

      你试过了吗:

      GCSettings.LatencyMode = GCLatencyMode.Batch;
      

      这应该会停止 GC 在其他线程上运行。

      MSDN

      禁用垃圾收集并发并回收对象 批量调用。这是最具侵入性的模式。此模式专为 以牺牲响应能力为代价的最大吞吐量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-22
        • 1970-01-01
        • 2013-02-11
        • 2012-08-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多