1

私は OpenGL を使用していますが、手動で破棄する必要があるアンマネージド オブジェクトがあります。(特にテクスチャと頂点バッファ)。

問題は、頂点バッファを解放する関数が絶対にメインスレッド (そのようなオブジェクトを作成または破棄できる唯一のスレッド) から呼び出されなければならないことです。

管理対象オブジェクトの IDisposable とデストラクタを既に正しく実装しています。ガベージ コレクターも関数を正しく呼び出します。しかし、ガベージ コレクターは別のスレッドで実行され、GC が解放関数 (DeleteBuffers(...)、DeleteTexture(...) など) を呼び出すとクラッシュするため、これはすべて失敗することになります。

そこで、これを解決するために 2 つのアイデアを思いつきました。

  1. 解放する必要があるオブジェクトをリストに追加し、メイン スレッドでそのリストを確認します。問題: 回避したい同期/ロックが必要です。おそらく BlockingCollection<> を使用しますか?

  2. どういうわけか、GC がメインスレッドを使用してその仕事を行うように強制します。

これを行う方法がわかりませんか?これらのオブジェクトを正しく処分するにはどうすればよいですか? 自分でクリーンアップする必要がありますか? (つまり、デストラクタの使用をやめて、常に自分でオブジェクトを解放しますか?)

4

2 に答える 2

1

アイデアは単純です。キューがあり (スレッドの安全性のために ConcurentQueue を使用します)、フィンライザーがこのキューを満たし、メイン ループがそれを空にします。

このリンクを試してください: 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 コンテキストを処理する方法を見つけることだけです。

于 2012-12-05T10:14:07.743 に答える
0

やってみました:

GCSettings.LatencyMode = GCLatencyMode.Batch;

これにより、他のスレッドでのGCの実行が停止します。

MSDN

ガベージコレクションの同時実行を無効にし、バッチ呼び出しでオブジェクトを再利用します。これは最も煩わしいモードです。このモードは、応答性を犠牲にして最大のスループットを実現するように設計されています。

于 2012-12-05T10:09:38.257 に答える