SDL2中SDL_Delay()触发SDL_QUIT退出时程序冻结的修复方法
问题根因
- 在
SDL_QUIT事件处理分支中提前调用了SDL_Quit()销毁了所有SDL运行资源,但此时主循环并未结束,后续执行的SDL_RenderPresent()、SDL_Delay()等API依赖已销毁的SDL环境,触发未定义行为导致窗口冻结。 - 单次调用
SDL_PollEvent()每次循环仅能处理事件队列中的第一个事件,存在事件遗漏风险。 - 当帧处理耗时超过16.666ms时,
floor(16.666f - elapsedMS)会返回负数,SDL_Delay()传入负数参数会产生异常。
修复方案
- 移除
SDL_QUIT分支中的SDL_Quit()调用,仅修改running变量标记循环结束,在主循环退出后统一执行资源销毁和SDL_Quit()调用。 - 用
while循环包裹SDL_PollEvent(),确保事件队列中所有待处理事件都被消费完毕。 - 对
SDL_Delay的输入参数做边界校验,仅当计算得到的延时值大于0时才执行延时,避免传入非法参数。
修复后完整代码
#include <SDL2/SDL.h> #include <math.h> const int WINDOW_WIDTH = 1000; const int WINDOW_HEIGHT = 750; int main(int argc, char *args[]) { if (SDL_Init(SDL_INIT_VIDEO) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: %s", SDL_GetError()); return 1; } SDL_Window *window; SDL_Renderer *renderer; SDL_Event e; bool running = true; if (SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: %s", SDL_GetError()); return 1; } while (running) { Uint64 start = SDL_GetPerformanceCounter(); // 循环处理所有待处理事件 while (SDL_PollEvent(&e)) { switch (e.type) { case SDL_QUIT: running = false; break; } } SDL_RenderPresent(renderer); Uint64 end = SDL_GetPerformanceCounter(); float elapsedMS = (end - start) / (float) SDL_GetPerformanceFrequency() * 1000.0f; int delayMS = (int)floor(16.666f - elapsedMS); // 仅当延时值合法时执行延时 if (delayMS > 0) { SDL_Delay(delayMS); } } // 统一销毁资源后退出 SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; }
内容的提问来源于stack exchange,提问作者Magikarpm
相关产品推荐
相关产品推荐

