To learn C# native interop, I've been working on an OpenGL wrapper. The OpenGL API itself is a state machine which is bound to a specific thread. When an object containing native resources is garbage collected, the finalizer is running in the GC thread, and cannot directly free the resources.
The workaround I currently have is to have a list in the context object, which the objects add their resources to and at a safe point in the draw loop it iterates through and frees them.
The problem with this, however, is that if the GC collects while it's iterating through that list, the foreach fails as the collection has been modified. I can't just put a mutex around the list as the GC is stop-the-world in most implementations and if the draw loop had locked it, it'd never complete the iteration and unlock it again.
Typically the MTBF is about two hours of gameplay, but if intentionally stress tested with a few thousand objects per second it happens in just a few seconds.
What might be the best approach here?