【问题标题】:Cleaning up when exiting an OpenGL app退出 OpenGL 应用程序时进行清理
【发布时间】:2011-02-10 21:35:08
【问题描述】:

我有一个我正在尝试修改的 OSX OpenGL 应用程序。当我创建整个应用程序时 调用了一堆初始化函数——包括我可以指定自己的鼠标和键盘处理程序等的方法。例如:

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(700, 700);
glutCreateWindow("Map Abstraction");
glutReshapeFunc(resizeWindow);
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
glutMouseFunc(mousePressedButton);
glutMotionFunc(mouseMovedButton);
glutKeyboardFunc(keyPressed);

在某些时候,我将控制权传递给 glutMainLoop 并且我的应用程序运行。在运行过程中,我创建了一大堆对象。我想把这些清理干净。有什么方法可以告诉 GLUT 在退出之前调用清理方法?

【问题讨论】:

  • 如果您希望清理 glut 应用程序:不要使用 glut。

标签: c++ macos opengl glut


【解决方案1】:

如果你这样称呼,在 freeglut 中:

glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION)

在进入主循环之前,当窗口关闭时,主循环函数将返回,您可以进行清理。

值得注意的是,在那个阶段 GL 上下文已经被销毁,因此您无法执行任何 GL 操作。

【讨论】:

  • 实际上值得注意的是上下文被破坏了!这就是你写这篇文章 18 个月后把我带到这里的原因。另一个不错的选择是 glutCloseFunc() 回调,它会在您关闭程序窗口后立即运行。上下文仍然存在于该函数中,因此您也可以正确地销毁那里的东西。
【解决方案2】:

我偶尔会为此而堕落,试图与 GLUT 一起玩。我尝试了所有我能做的事情,包括 IIRC 通过主函数中捕获的异常退出 glutMainLoop 但是......

当使用glutMainLoop

我的解决方案如下:创建一个全局 Context 对象,该对象将是您所有资源的所有者,并在析构函数中释放这些资源。

这个全局的Context对象析构函数会在退出main后立即被调用。

重要的是Context 是一个全局变量,而不是在主函数中声明的变量,因为我仍然无法理解的原因(我仍然看不到这种实现选择的兴趣),glutMainLoop 不会返回。

在我的 Linux 机器(Ubuntu)中,析构函数被正确调用。我想它在 Windows 和 MacOS 上也应该以同样的方式工作。

请注意,这是 Francisco Soto 的 atexit() 解决方案的 C++ 版本,没有可能的限制。

使用glutMainLoopEvent

显然,一些实现有一个 glutMainLoopEvent 可以用来代替调用 glutMainLoop。

http://openglut.sourceforge.net/group__mainloop.html#ga1

glutMainLoopEvent 只会解决待处理的事件,然后返回。因此,您必须在对 glutMainLoopEvent 的调用周围提供事件循环(for(;;) 构造),但是这样,您可以使用 GLUT 并且仍然可以控制事件循环,并在需要时释放资源。

【讨论】:

    【解决方案3】:

    如果您使用 C/C++,也许您可​​以使用atexit() 调用?

    【讨论】:

    • 是的,我应该提到我正在使用 C++。我正在寻找基于 atexit 的解决方案,但它不如指定清理回调那么好。无论如何,这是一个很好的建议。谢谢!
    【解决方案4】:

    通常您不需要这样做;只是退出应用程序将拆除您分配的任何资源。即使您已捕获屏幕,它也应该恢复正常。

    【讨论】:

    • 我不明白; GLUT 怎么知道我 malloc 了什么?
    • 这不是 GLUT 做的,是操作系统。您的应用程序关闭,操作系统自行清理。
    • -1。这是非常糟糕的做法。它鼓励草率的编程实践,例如不正确地跟踪你的记忆。如果您正确编写了应用程序,您应该能够轻松展开内存分配,而无需依赖操作系统来清理。
    • +1 平衡。如果它的坏习惯并不重要。它是如何工作的。 glutModalLoop 函数不返回,因此 NSApplication::Run 不返回。在框架已经承诺不进行任何清理的情况下,试图强制应用程序对象进行清理是一种浪费。
    • @NicholasRiley - 我没有赞成或反对你的答案。没有反对意见 - 我知道的所有现代操作系统(不能说每个)都在为你做资源清理 - 如果你在 用户空间 中运行。让 os 为您执行此操作并没有错,特别是如果 os 供应商鼓励您这样做(您的 Apple 示例)。当应该在 用户空间 中的此类系统上工作的代码被移植到其他系统时,或者在内核空间中运行,或者只是被其他期望的编码器重新使用时,就会出现问题对象在终止时释放其资源。或者别的什么..
    【解决方案5】:

    我最终使用了上面 paercebal 的答案,以及他之前尝试在 glutMainLoop() 周围使用 try/catch 块的尝试。为什么?因为无论它如何关闭,我都想正确清理。如果应用程序干净地退出,全局 Context 对象将被正确销毁,如果您通过关闭窗口(或在 OS X 上退出应用程序)来关闭应用程序,就会发生这种情况。但是,如果您在启动它的终端中按 ctrl-C(或向其发送 SIGINT),则不会进行清理。为了解决这个问题,我在代码中添加了以下内容:

    static bool exitFlag = false;
    
    static void sighandler(int sig) {
      exitFlag = true;
    }
    
    static void idleFunc() {
      if(exitFlag) {
        throw NULL;
      }
    }
    

    然后在main()中:

    signal(SIGINT, sighandler);
    glutIdleFunc(idleFunc);
    
    try {
      glutMainLoop();
    } catch(...) {}
    

    这不是最漂亮的代码,但它确实处理了正确退出程序的两种情况。

    一个 catch(不是双关语)——如果您正常关闭窗口/退出应用程序,您在 catch() 块之后放置的任何代码都不会被调用。您必须将清理代码放在全局 Context 对象中,如 paercebal 的答案所示。这段代码所做的就是允许使用 SIGINT 信号退出 glutMainLoop()。

    我认为这里真正的教训是,对于任何非常复杂的事情,GLUT 都不会削减它。

    【讨论】:

      猜你喜欢
      • 2011-12-16
      • 1970-01-01
      • 1970-01-01
      • 2012-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多