使用Application.DoEvents“模拟”Application.Run

时间:2010-03-30 17:35:36

标签: c# forms opengl message-pump

我遇到了麻烦。我正在尝试使用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();
}

这段代码由Main例程执行。实际上,我有一个内核类列表,它们在不同的线程中运行,这些线程处理一个Form,用于在OpenGL中进行渲染。我需要使用屏障同步所有内核线程,这非常有效。 当然,我需要在主线程(主例程)中处理Form消息,对于每个创建的Form,我确实调用Application.DoEvents()来完成这项工作。

现在我必须修改上面的代码片段,使其具有一个通用的Form(简单对话框),而不像App.Run那样消耗100%的CPU调用Application.DoEvents()。

目标应该是让上面的代码段在到达时处理消息,并在必要时发出渲染(释放屏障),而不是试图获得最大FPS;应该有可能切换到严格的循环来尽可能地渲染。

怎么可能?

注意:上面的代码片段必须在Main例程中执行,因为OpenGL上下文是在主线程上创建的。在一个单独的线程中移动代码片段并调用Application.Run是非常不稳定和错误的......

3 个答案:

答案 0 :(得分:1)

不要这样做 - 这些东西非常复杂,我很确定你自己实现它只会遇到麻烦。

你不能用Application.AddMessageFilter()来实现你需要的东西吗?

答案 1 :(得分:1)

在循环中调用Application.DoEvents()没有任何根本错误。这就是Form.ShowDialog()所做的。需要采取措施确保用户不会遇到麻烦:它会禁用除对话框以外的所有窗口,因此用户无法退出应用程序或再次启动对话框。

您需要创建自己的标记,设置一个全局标记,指示您的主窗口已关闭,这样您可以立即退出循环,而无需在从您身下拉出地毯时再调用任何代码。

您需要使用处理器以避免100%的CPU负载。最简单的方法是调用Thread.Sleep(1)。请在this thread中查看我的答案。

答案 2 :(得分:0)

如果您要构建这样的消息循环,您应该PInvoke实际的Win32消息处理函数(这是Application.Run在幕后所做的全部 - 它有一个名为UnSafeNativeMethods的内部类映射一个他们一堆)。

如果您不需要在消息调用之间继续处理 - 换句话说,如果您的线程在没有主动处理消息时可以安全地休眠 - 那么从User32.dll绑定WaitMessage并且把它放在一个循环中:

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

如果您需要更多帮助,请告诉我们。我现在正在重新安装VS,或者我发布了一个示例应用程序,展示了如何进行绑定和PInvoke。