3

困っています。Application.DoEventsを使用してApplication.Runの呼び出しをエミュレートしようとしています...これは悪いように聞こえますが、質問に対する代替ソリューションも受け入れます...

Application.Runのようにメッセージポンプを処理する必要がありますが、メッセージ処理の前後にコードを実行する必要があります。これがコードの主な重要なスニペットです。

// Create barrier (multiple kernels synchronization)
sKernelBarrier = new KernelBarrier(sKernels.Count);

foreach (RenderKernel k in sKernels) {
    // Create rendering contexts (one for each kernel)
    k.CreateRenderContext();
    // Start render kernel kernels
    k.mThread = new Thread(RenderKernelMain);
    k.mThread.Start(k);
}

while (sKernelBarrier.KernelCount > 0) {
    // Wait untill all kernel loops has finished
    sKernelBarrier.WaitKernelBarrier();
    // Do application events
    Application.DoEvents();
    // Execute shared context services
    foreach (RenderKernelContextService s in sContextServices)
        s.Execute(sSharedContext);

    // Next kernel render loop
    sKernelBarrier.ReleaseKernelBarrier();
}

このコードスニペットは、メインルーチンによって実行されます。実は、別々のスレッドで実行されるカーネルクラスのリストがあります。これらのスレッドは、OpenGLでレンダリングするためのフォームを処理します。バリアを使用してすべてのカーネルスレッドを同期する必要がありますが、これは完全に機能します。もちろん、作成されたすべてのフォームについて、メインスレッド(メインルーチン)でフォームメッセージを処理する必要があります。実際、Application.DoEvents()を呼び出してジョブを実行します。

ここで、上記のスニペットを変更して、Application.RunのようにApplication.DoEvents()を呼び出すCPUを100%消費せずに、共通のフォーム(単純なダイアログボックス)を作成する必要があります。

目標は、上記のスニペットが到着時にメッセージを処理し、最大FPSを取得しようとせずに、必要な場合にのみレンダリングを発行する(バリアを解放する)ことです。可能な限りレンダリングするために、厳密なループに切り替える可能性があるはずです。

どうしてそれが可能でしょうか?

注:OpenGLコンテキストはメインスレッドで作成されるため、上記のスニペットはメインルーチンで実行する必要があります。別のスレッドでスニペットを移動し、Application.Runを呼び出すと、非常に不安定でバグが発生します...

4

3 に答える 3

1

それをしないでください-これはかなり複雑で、自分で実装するのに問題があるだけだと確信しています。

必要なものを実装するために使用できませんApplication.AddMessageFilter()か?

于 2010-03-30T17:40:34.120 に答える
1

ループでApplication.DoEvents()を呼び出すことには、根本的な問題はありません。これがForm.ShowDialog()の機能です。ユーザーがトラブルに巻き込まれないようにするための対策が講じられています。ダイアログ以外のすべてのウィンドウが無効になるため、ユーザーはアプリケーションを終了したり、ダイアログを再開したりできなくなります。

独自のフラグを作成し、メインウィンドウが閉じたことを示すグローバルフラグを設定して、ラグが下から引き出されたときにコードを呼び出さなくてもすぐにループを終了できるようにする必要があります。

100%のCPU負荷を回避するには、プロセッサを譲る必要があります。これを行う最も簡単な方法は、Thread.Sleep(1)を呼び出すことです。例については、このスレッドで私の答えを確認してください。

于 2010-03-30T18:18:16.497 に答える
0

このようなメッセージループを構築する場合は、実際のWin32メッセージ処理関数をPInvokeする必要があります(これは、Application.Runがバックグラウンドで実行しているすべての関数です。UnSafeNativeMethodsという内部クラスがあり、それらの関数をマップします。 )。

メッセージ呼び出しの合間に処理を続ける必要がない場合、つまり、メッセージをアクティブに処理していないときにスレッドが安全にスリープできる場合は、User32.dllからWaitMessageをバインドし、次のようなループに入れます。

while (WaitMessage())
{
  Application.DoEvents();
}

さらにサポートが必要な場合はお知らせください。現在、VSの再インストールの最中です。または、バインディングとPInvokeの実行方法を示すサンプルアプリケーションを投稿します。

于 2010-03-30T17:55:28.617 に答える