如何让C++线程与主while循环完全并行且独立运行
问题根因
- 你当前主循环阻塞的核心原因是调用了
std::future::get(),该方法会同步等待异步任务执行完成后才会继续往下执行,所以必须等所有计时器线程跑完才会进入下一轮while循环。 - 两个异步任务同时修改同一个
chrono对象,无锁保护存在数据竞争,属于C++未定义行为,会出现计时异常。 - 多线程同时向
std::cout输出内容,没有同步保护会导致输出乱序、错乱。 - 你在while循环内反复创建新的异步任务,且持有future不释放,还会导致内存持续增长。
调整方案
- 用
std::thread替代std::async实现完全独立的后台线程,启动后调用detach()脱离主线程管控,自主运行。 - 每个计时器独立维护自身的计时变量,不要共享同一个计时对象,避免数据竞争。
- 加互斥锁保护
std::cout等共享资源,保证多线程输出正常。 - 计时器线程只在程序初始化时启动一次,不要在while循环内重复创建。
修改后的mychrono.hpp
#include <time.h> #include <iostream> #include <sstream> #include <mutex> #ifndef mychrono_hpp #define mychrono_hpp // 全局互斥锁,保护cout输出 extern std::mutex g_io_mutex; class Chronometer { private: int hour, min, sec; bool is_running; // 控制计时器运行状态 public: Chronometer(); void start_chrono(); // 无需传入外部chrono,自身维护计时数据 void stop_chrono(); // 停止计时器接口 friend std::ostream& operator<<(std::ostream& flux, const Chronometer& t); ~Chronometer(); }; #endif
修改后的mychrono.cpp
#include "mychrono.hpp" #include <unistd.h> #include <thread> std::mutex g_io_mutex; Chronometer::Chronometer() : hour(0), min(0), sec(0), is_running(false) { } void Chronometer::start_chrono() { is_running = true; while(is_running) { sleep(1); sec++; if(sec > 59) { min++; sec = 0; } if(min > 59) { hour++; sec = 0; min = 0; } // 加锁保护cout输出避免乱序 std::lock_guard<std::mutex> lock(g_io_mutex); std::cout << "chrono: " << *this << std::endl; } } void Chronometer::stop_chrono() { is_running = false; } std::ostream& operator<<(std::ostream& flux, const Chronometer& t) { flux << t.hour << ":" << t.min << ":" << t.sec; return flux; } Chronometer::~Chronometer() { stop_chrono(); }
修改后的main.cpp
#include <iostream> #include <thread> #include <vector> #include <unistd.h> #include "mychrono.hpp" int main() { std::vector<Chronometer*> car_crono; for(int i = 0; i < 2; i++) { car_crono.push_back(new Chronometer); // 启动计时器线程,detach后在后台完全独立运行 std::thread t(&Chronometer::start_chrono, car_crono[i]); t.detach(); } // 主循环完全独立运行,不需要等待任何线程 while (1) { std::lock_guard<std::mutex> lock(g_io_mutex); std::cout << "hello-world" << std::endl; // 可调整sleep时间控制hello-world的打印频率 sleep(1); } // 实际项目添加退出逻辑后可执行资源清理 for(auto crono : car_crono) { delete crono; } car_crono.clear(); return 0; }
调整后计时器线程和主循环完全并行运行,互不阻塞,同时加锁保证了输出不会乱码。
内容的提问来源于stack exchange,提问作者Thibault Grard
相关产品推荐
相关产品推荐

