C++多线程绘图卡顿且偶发崩溃问题技术求助
多线程游戏程序崩溃与显示不流畅问题
我设计了一个多线程游戏程序:
- 1个线程负责车辆移动
- 1个线程负责用户输入
- 1个线程利用输入控制人物移动
每完成一步后绘制车辆与人物。单线程模式下运行正常,但启用多线程后,程序有时会崩溃,且车辆与人物的显示不流畅。
绘图函数逻辑是擦除旧位置并在新位置重新绘制。
以下是我的代码:
void CGame::startGame() { char user_input; bool input_ready = false; bool draw_finish = true; setGame(); CPeople people; //g.runGame(); char inp; condition_variable cv, cv2; mutex m; thread t1([&cv, &m, &user_input, &input_ready, &draw_finish, &cv2]() { while (true) { unique_lock<mutex> lock(m); cv2.wait(lock, [&draw_finish] {return draw_finish; }); user_input = CConsole::getInput(); input_ready = true; draw_finish = false; cv.notify_one(); } }); thread t3([&people, &cv, &m, &user_input, &input_ready, &draw_finish, &cv2]() { while (true) { unique_lock<mutex> lock(m); cv.wait(lock, [&input_ready] { return input_ready; }); people.peopleMoving(user_input); //this_thread::sleep_for(chrono::milliseconds(10)); draw_finish = true; input_ready = false; cv2.notify_one(); } }); //INPUT.get(); mutex m2; thread t2([this, &m2, &cv, &draw_finish]() { // unique_lock<mutex> lock(m); m2.lock(); this->runObstacle(); //this_thread::sleep_for(chrono::milliseconds(100)); m2.unlock(); }); //while (true) { // inp = CConsole::getInput(); // people.peopleMoving(inp); // //std::this_thread::sleep_for(std::chrono::seconds()); //} t1.join(); t2.join(); t3.join(); // }
问题分析与修复方案
1. 核心问题排查
- 车辆线程逻辑失效:线程
t2仅执行一次runObstacle()就终止,且直接调用m2.lock()而非RAII风格的unique_lock,一旦runObstacle()抛出异常,锁会永久无法释放,引发死锁风险。同时该线程与其他线程完全无同步,导致车辆移动和人物移动、绘图时序彻底混乱,这是显示卡顿的核心原因。 - 控制台资源竞争:绘图操作(擦除/绘制)属于共享控制台资源,当前代码未对其加锁保护,多线程同时操作会导致输出错乱,甚至触发程序崩溃。
- 输入线程锁阻塞:
CConsole::getInput()在持有锁的状态下调用,若该函数是阻塞式等待用户输入,会导致其他线程完全无法获取锁,卡死整个同步流程。
2. 具体修复步骤
(1)重构车辆移动线程,加入同步逻辑
让车辆线程与其他线程保持时序同步,确保每一步都配合绘图流程:
// 替换原t2代码 thread t2([this, &m, &draw_finish, &cv2]() { while (true) { unique_lock<mutex> lock(m); cv2.wait(lock, [&draw_finish] { return draw_finish; }); this->runObstacle(); // 执行车辆移动逻辑 draw_finish = false; cv.notify_one(); // 通知人物处理线程 } });
(2)保护控制台绘图资源
在所有涉及控制台绘图的函数中,使用同一个互斥锁保护操作:
// 在CGame类中添加成员:mutex draw_mutex; void CPeople::peopleMoving(char input) { unique_lock<mutex> lock(g_game->draw_mutex); // 假设g_game是CGame实例指针 // 擦除旧位置代码 // 计算新位置 // 绘制新位置代码 } void CGame::runObstacle() { unique_lock<mutex> lock(draw_mutex); // 擦除旧车辆位置代码 // 移动车辆 // 绘制新车辆位置代码 }
(3)调整输入线程的锁持有时机
将输入获取操作放到锁外,避免阻塞整个同步流程:
thread t1([&cv, &m, &user_input, &input_ready, &draw_finish, &cv2]() { while (true) { char input = CConsole::getInput(); // 先获取输入,不持有锁 unique_lock<mutex> lock(m); cv2.wait(lock, [&draw_finish] {return draw_finish; }); user_input = input; input_ready = true; draw_finish = false; cv.notify_one(); } });
(4)统一线程循环逻辑
确保三个线程持续循环,严格遵循「输入/车辆移动 → 人物移动 → 绘图完成 → 下一轮」的时序,避免混乱。
3. 额外优化建议
- 抽离独立绘图线程:不要让业务线程各自处理绘图,统一由一个线程负责所有绘图操作,彻底消除控制台资源竞争。
- 添加线程退出机制:设置
bool running标志,游戏结束时所有线程检测到标志后退出循环,避免程序无法正常终止。
内容的提问来源于stack exchange,提问作者HCMUSer
相关产品推荐
相关产品推荐

