【发布时间】:2011-09-04 13:08:30
【问题描述】:
我正在编写一个 3D 模型查看器应用程序作为一个爱好项目,同时也是一个测试平台来尝试不同的渲染技术。我使用 SDL 处理窗口管理和事件,使用 OpenGL 进行 3D 渲染。我的程序的第一次迭代是单线程的,并且运行良好。但是,我注意到单线程程序导致系统变得非常缓慢/滞后。我的解决方案是将所有渲染代码移动到不同的线程中,从而释放主线程来处理事件并防止应用程序变得无响应。
这个解决方案间歇性地工作,由于主要来自 X 窗口系统的一组不断变化的(在我看来很奇怪)错误,程序经常崩溃。这让我质疑我最初的假设,即只要我所有的 OpenGL 调用都发生在创建上下文的线程中,一切都应该正常。在花了一天的大部分时间在互联网上寻找答案之后,我彻底被难住了。
更简洁:是否可以在主线程以外的线程中使用 OpenGL 执行 3D 渲染?我仍然可以在此配置中使用跨平台窗口库,例如 SDL 或 GLFW 吗?有没有更好的方法来做我想做的事情?
到目前为止,我一直在使用 C++ 在 Linux (Ubuntu 11.04) 上进行开发,但如果有更适合这些语言的解决方案,我也对 Java 和 Python 感到满意。
更新:根据要求,一些澄清:
- 当我说“系统变得迟缓”时,我的意思是与桌面交互(拖动窗口、与面板交互等)变得比平时慢得多。移动我的应用程序的窗口需要几秒钟的时间,而其他交互也慢到令人讨厌。
- 至于对合成窗口管理器的干扰...我正在使用 Ubuntu 11.04 附带的 GNOME shell(暂时远离 Unity...),我找不到任何禁用桌面效果的选项,例如在以前的发行版中有。我认为这意味着我没有使用合成窗口管理器......尽管我可能错了。
- 我相信“X 错误”是由于我在终端收到的错误消息导致的服务器错误。更多详情如下。
我的应用程序的多线程版本遇到的错误:
XIO:X 服务器“:0.0”上的致命 IO 错误 11(资源暂时不可用) 在 73 个请求(73 个已知已处理)之后,剩余 0 个事件。
失败请求的 X 错误:BadColor(无效的颜色图参数) 失败请求的主要操作码:79(X_FreeColormap) 失败请求中的资源 ID:0x4600001 失败请求序列号:72 输出流中的当前序列号:73
游戏:../../src/xcb_io.c:140:dequeue_pending_request:断言 `req == dpy->xcb->pending_requests' 失败。 中止
我总是得到上述三个错误之一,我得到的一个错误显然是随机的,这(在我看来)似乎证实了我的问题确实源于我对线程的使用。请记住,我是边学边学的,所以很有可能在我的无知中我有一些相当愚蠢的事情。
解决方案: 对于遇到类似问题的任何人,我解决了我的问题,方法是将我对 SDL_Init(SDL_INIT_VIDEO) 的调用移至渲染线程,并使用互斥锁锁定上下文初始化。这确保了上下文是在将要使用它的线程中创建的,并且它可以防止主循环在初始化任务完成之前启动。启动过程的简化大纲:
1) 主线程初始化struct,它将在两个线程之间共享,并且包含一个互斥锁。
2) 主线程产生渲染线程并休眠一小段时间(1-5ms),给渲染线程时间来锁定互斥锁。在此暂停之后,主线程在尝试锁定互斥锁时阻塞。
3) 渲染线程锁定互斥体,初始化SDL的视频子系统并创建OpenGL上下文。
4) 渲染线程解锁互斥锁并进入其“渲染循环”。
5)主线程不再被阻塞,所以它在完成初始化步骤之前锁定和解锁互斥锁。
请务必阅读答案和 cmets,那里有很多有用的信息。
【问题讨论】:
-
不确定 X,但在 Win32 上这是允许的。上下文只能在一个线程上处于活动状态,但听起来您正在遵守该规则。
-
这是我从研究中得到的印象。理想情况下,我真的很想让我的应用程序是跨平台的......如果没有其他原因,我只想尽可能少地处理 Windows API =P
-
这不能怪你……尽管我发现 Win32 API(事件分派)的这些方面要优越得多。我希望 Linux 有一个
MsgWaitForMultipleObjectsEx等价物(可能名称更短)。与poll类似,但能够等待文件、子进程、计时器、线程、互斥体和 UI 消息。 -
您应该在解决方案的第 1 步中小心。 “短暂时间”可能不够长,因此您应该使用一个标志来指示渲染线程是否已初始化。在主线程中,检查此标志,如果未设置,则线程应等待来自渲染线程的信号/广播。
-
@BenVoigt 我知道这是一个旧线程,但你不应该比较 linux 和 win32 api。你应该比较win32 api和x11
标签: multithreading opengl sdl