“模仿”使用 Application.DoEvents 运行 Application.Run

发布于 2024-08-27 07:30:09 字数 1400 浏览 8 评论 0 原文

我遇到麻烦了。我正在尝试使用 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 那样消耗 100% 的 CPU 调用 Application.DoEvents()。

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

怎么可能?

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

I'm getting in trouble. I'm trying to emulate the call Application.Run using Application.DoEvents... this sounds bad, and then I accept also alternative solutions to my question...

I have to handle a message pump like Application.Run does, but I need to execute code before and after the message handling. Here is the main significant snippet of code.

// 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();
}

This snippet of code is execute by the Main routine. Pratically I have a list of Kernel classes, which runs in separate threads, these threads handle a Form for rendering in OpenGL. I need to synchronize all the Kernel threads using a barrier, and this work perfectly.
Of course, I need to handle Form messages in the main thread (Main routine), for every Form created, and indeed I call Application.DoEvents() to do the job.

Now I have to modify the snippet above to have a common Form (simple dialog box) without consuming the 100% of CPU calling Application.DoEvents(), as Application.Run does.

The goal should be to have the snippet above handle messages when arrives, and issue a rendering (releasing the barrier) only when necessary, without trying to get the maximum FPS; there should be the possibility to switch to a strict loop to render as much as possible.

How could it be possible?

Note: the snippet above must be executed in the Main routine, since the OpenGL context is created on the main thread. Moving the snippet in a separated thread and calling Application.Run is quite unstable and buggy...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

弃爱 2024-09-03 07:30:09

在循环中调用 Application.DoEvents() 并没有什么根本性的错误。这就是 Form.ShowDialog() 的作用。它采取对策来确保用户不会遇到麻烦:它禁用除对话框之外的所有窗口,以便用户无法退出应用程序或再次启动对话框。

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

您需要让出处理器以避免 100% CPU 负载。最简单的方法是调用 Thread.Sleep(1)。检查我的答案 此线程举个例子。

There isn't anything fundamentally wrong with calling Application.DoEvents() in a loop. That's what Form.ShowDialog() does. It takes counter-measures to ensure the user cannot get into trouble: it disables all windows other than the dialog so the user cannot exit the application or start the dialog again.

You'll need to create your own, set a global flag that indicates that your main window was closed so you can immediately exit the loop without calling any more code when the rug is pulled out from under you.

You'll need to yield the processor to avoid 100% CPU load. The easiest way to do that is by calling Thread.Sleep(1). Check my answer in this thread for an example.

金橙橙 2024-09-03 07:30:09

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

您不能使用应用程序吗? AddMessageFilter() 来实现您需要的功能?

Don't do it - this stuff is pretty complex and I'm pretty sure you get nothing but trouble for implementing it yourself.

Can't you use Application.AddMessageFilter() to implement what you need?

北风几吹夏 2024-09-03 07:30:09

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

如果您不需要在消息调用之间保持处理(换句话说,如果您的线程在不主动处理消息时可以安全地休眠),则绑定 WaitMessage 来自 User32.dll 并将其放入循环中,例如:

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

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

If you're going to build a message loop like this, you should PInvoke the actual Win32 message handling functions (which is all that Application.Run is doing behind the scenes -- it has an internal class called UnSafeNativeMethods that maps a bunch of them).

If you don't need to keep processing between message calls -- in other words, if it's safe for your thread to sleep when it's not actively handling a message -- then bind WaitMessage from User32.dll and put it in a loop like:

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

If you need more help let me know. I'm in the middle of a VS reinstall right now or I'd post a sample application showing how to do the binding and PInvoke.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文