我遇到了麻烦。我正在尝试使用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是非常不稳定和错误的......
答案 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。