C++定时器:Start与Stop功能正常,Restart无法终止线程
问题原因分析
问题出在Restart()函数的执行逻辑上:调用Stop()后立刻执行Start(),此时旧线程还没完成退出流程——Stop()只是设置running=false并通知条件变量,但旧线程响应这个信号并退出需要时间,而Start()马上又把running重新设为true,导致旧线程的wait_for条件判断失效,继续执行循环;同时新线程被创建,最终出现多线程同时运行的情况。
单独调用Stop()时,主线程会等待用户输入,这段空档足够旧线程响应退出信号并终止;但Restart()里Stop()和Start()连续执行,没有给旧线程留出退出的时间窗口。
解决方案
方案1:保存线程对象,确保旧线程完全退出后再启动新线程
放弃detach(),改用std::thread对象保存线程实例,在Stop()和Start()中等待旧线程结束,从根本上避免线程失控。
修改后的完整代码:
#include <iostream> #include <thread> #include <condition_variable> #include <chrono> #include <atomic> using namespace std; // 用原子变量保证running的线程安全读写 atomic<bool> running = false; unsigned int interval = 5000; condition_variable cv_work; mutex mu_cv_work; // 保存线程对象,避免detach导致的线程管理失控 thread worker_thread; void Start() { unique_lock<std::mutex> lock(mu_cv_work); running = true; lock.unlock(); // 启动新线程前,确保旧线程已经结束 if (worker_thread.joinable()) { worker_thread.join(); } worker_thread = thread([]{ cout << "new thread" << '\n'; while (running) { cout << "work..." << '\n'; unique_lock<std::mutex> lock(mu_cv_work); cout << "sleep" << '\n'; // 简化条件判断逻辑 if (cv_work.wait_for(lock, chrono::milliseconds(interval), []{return !running;})) { cout << "exit thread" << '\n'; return; } cout << "done sleeping" << '\n'; } }); } void Stop() { unique_lock<std::mutex> lock(mu_cv_work); running = false; lock.unlock(); cv_work.notify_one(); // 等待线程完全退出 if (worker_thread.joinable()) { worker_thread.join(); } } void Restart() { Stop(); Start(); } int main() { Start(); cout << "press to Stop" << '\n'; cin.get(); Stop(); cout << "press to Start" << '\n'; cin.get(); Start(); cout << "press to Restart" << '\n'; cin.get(); Restart(); return 0; }
核心修改点:
- 用
atomic<bool>替代普通bool,消除running变量的线程安全隐患 - 新增
worker_thread变量管理线程实例,避免detach()导致的线程失控 - 在
Stop()和Start()中检查线程可连接状态,等待旧线程完全退出后再执行下一步操作
方案2:临时等待(不推荐)
如果必须保留detach(),可以在Restart()中加入短暂等待,给旧线程留出退出时间,但这种方式依赖硬件性能,可靠性差,仅作为临时 workaround:
void Restart() { Stop(); this_thread::sleep_for(chrono::milliseconds(100)); // 等待旧线程退出 Start(); }
验证结果
修改后运行代码,Restart()会先触发旧线程输出exit thread,再创建新线程运行,完全符合期望输出。
内容的提问来源于stack exchange,提问作者poorharambe1
相关产品推荐
相关产品推荐

