c++ - 从分离线程停止主游戏循环的最佳方法
问题描述
我正在使用 SDL 开发 C++ 游戏。我开始关注Lazyfoo 的教程,并一直在使用 XCode 在 MacOS 中构建它。这个周末,我一直在查看是否可以在 Visual Studio 2019 中的 Windows 上编译它。我已经成功了,但我不确定我必须做出的改变之一。
游戏使用 ImageMagick (Magick++) 进行一些绘图,然后使用 SDL 将其作为纹理存储在视频卡内存中(SDL 自己的绘图功能还不够)。绘图部分非常慢,但不需要同步发生,所以我选择将该过程放在它自己的线程中,这在我的 Mac 上工作得非常好。
现在我在 Windows 上运行它,当游戏试图绘制一个新角色时,我偶尔会看到崩溃。我将其缩小到SDL_CreateTextureFromSurface()
,它从线程内调用并使用从 Magick++ 图像创建的表面创建新纹理。这只发生在我使用多线程时,如果我禁用它(并在它绘制某些东西时杀死我的帧率),它工作得很好。
我查看了互斥锁,但所有建议都建议在线程上使用join
,该线程会main()
在整个绘图期间阻塞,并使其毫无意义。我认为我很有可能误解了这一点!
bool
相反,我在一个作为对线程的引用传递的类中设置了两个s。当SDL_Thread_Waiting
被线程设置true
为时,游戏循环main()
暂时暂停并设置SDL_Main_Paused
为true
告诉线程它可以安全地访问渲染器。然后线程设置SDL_Main_Paused
为false
完成时,游戏循环继续。
这意味着 ImageMagick 可以在它自己的线程中尽可能慢,但在最后一步,我可以短暂暂停主游戏以允许存储纹理而不会发生任何崩溃。
下面的示例代码。游戏在这一点上非常庞大,但这应该显示我在做什么:
// class.hpp
Class Game {
Public:
bool is_running;
bool SDL_Thread_Waiting = false;
bool SDL_Main_Paused = false;
// ...
}
// main.cpp
Game game;
int main(int argc, char* argv[]) {
game.is_running = true;
while (game.is_running) {
// Regular game stuff!
if (game.SDL_Thread_Waiting) {
game.SDL_Main_Paused = true;
while (game.SDL_Main_Paused) {
// do.. nothing?
}
}
}
// Threaded bits
void generate_character() {
std::thread th(make_texture, std::ref(game));
th.detach();
}
SDL_Texture* make_texture(Game& game) {
// Heavy lifting by ImageMagick goes here
SDL_Thread_Waiting = true;
while (!SDL_Main_Paused) {
std::this_thread::sleep_for(std::chrono::milliseconds(25));
}
// SDL_CreateTextureFromSurface()
SDL_Main_Paused = false;
SDL_Thread_Waiting = false;
return texture;
}
这是从分离的线程中短暂阻止主游戏循环的合适方法吗?我是不是误会mutex
了,这会更适合这里吗?
我对 C++ 和 SDL 很陌生,如果我的整个问题是基于进一步的误解,我深表歉意!
解决方案
您所描述的是互斥体行为。您已经实现了糟糕的自旋锁 - 这可能会因为锁变量上的错误同步而失败(一个线程可能会设置变量但其他线程尚未看到此更改),并且在锁定时会浪费 CPU 周期,因为它会一直在循环中旋转。使用SDL_mutex
or std::mutex
,它们似乎正是您想要的。
至于从多个线程访问渲染器 - 嗯,不太好。SDL 文档明确指出您确实不应该这样做(除非您完全确定正在使用 SDL 的渲染器实现并且知道该实现的行为方式)。考虑改变您的方法 - 例如,在单独的线程中渲染到内存缓冲区/表面,然后发出信号,以便渲染线程可以获取缓冲区并将其转换为纹理。您甚至可以在此处进行双缓冲以最大程度地减少停顿。
有些事情可以改进但需要更多的工作:创建线程不是免费的,为什么不创建一次并等待 mutex/semaphore/condvar 信号来渲染下一帧?SDL_CreateTextureFromSurface
假设静态纹理,为什么不创建一次流纹理并使用SDL_LockTexture
&&更新它memcpy
?
推荐阅读
- python-3.x - Selenium WebDriver 截图不捕获网页页脚
- angular - 插值不适用于点击方法
- image - 如何通过 http post 上传 QPixmap 图像?
- vb.net - VB.net Crystal 报表导出为 html 并使用 Outlook 作为 html 邮件正文发送
- sql - 如何根据月份参数值将数据从一年的开始月份拉到给定月份
- swift - 如何将 AttributedString 转换为 NSMutableString Swift?
- java - 当 jar 位于 zip 文件中时,如何过滤 jar 中的特定文件夹?
- javascript - 我可以将 jQuery UI 分类在文档上吗?
- python - 如何处理 HTTP 服务器中的多个请求?
- python - ImportError:没有名为 json 的模块