简体   繁体   中英

Force GC to use another thread-context

I'm working with OpenGL and there are unmanaged objects I need to dispose of manually. (Specifially textures and vertex-buffers).

The problem is, that the function that frees a vertexbuffer absolutely has to be called from the main-thread (the only thread that can create or destroy such objects).

I already implemented IDisposable and the destructors for my managed objects correctly. The garbage-collector also calls the functions correctly. But all this is bound to fail, because the garbage-collector runs on a different thread and when the GC calls the freeing-functions (DeleteBuffers(...), DeleteTexture(...), etc.) it crashes.

So I came up with 2 ideas to solve this:

  1. Add the objects that have to be freed to a list, then check that list in the main thread. Problem: Requires synchronisation / locking which I want to avoid. Maybe use a BlockingCollection<> ?

  2. Somehow force the GC to use the main-thread to do its job.

Is there a way which I don't know to do this? How should I dispose those objects correctly? Do I have to cleanup myself? (meaning I stop using the destructor and always free the objects myself?)

the idea is simple you have a Queue (Use ConcurentQueue for thread safety) have your finlizers fill this queue and your main loop empty it.

try this link: 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 is a queue that holds references to OpenGL resources. It is visited regularly during program execution, disposing data contained therein. Note that the 'else' clause will never be executed, unless you actually forget to release resources. This is the best of both worlds: you can release resources manually (with no performance hit), but the garbage collector will still clean up after you if you forget something. Even better, the implementation is dead simple! Now, we only need to find out how to handle multiple OpenGL contexts.

Have you tried:

GCSettings.LatencyMode = GCLatencyMode.Batch;

This should stop GC running on other threads.

MSDN

Disables garbage collection concurrency and reclaims objects in a batch call. This is the most intrusive mode. This mode is designed for maximum throughput at the expense of responsiveness.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM