C++11多线程间向长期运行函数传递状态的方案咨询
嘿,这个场景我太熟了!刚好在C++11环境下有几个特别贴合你需求的方案,结合你的描述给你捋清楚:
方案1:线程安全队列+轮询(你的对象工厂思路的细化)
你想到的“带内部状态队列的对象工厂”方向完全靠谱,这刚好匹配你的核心需求:状态可以随时攒下来,sub_main在自己的逻辑循环里统一处理,完美满足“至多单一位置处理”的要求,而且实现起来简单,完全不用纠结极致性能。
具体怎么搞呢?你可以封装一个StatusNotifier类,内部用std::mutex保护std::queue,对外提供两个接口:一个给其他线程推送状态,一个给sub_main轮询取状态。代码大概是这样:
#include <mutex> #include <queue> #include <utility> // C++11没有std::optional,这里用输出参数替代,也可以用boost::optional class StatusNotifier { private: std::mutex mtx; std::queue<YourStatusType> status_queue; // 替换成你实际的状态类型 public: // 其他线程调用:推送状态 void push_status(YourStatusType status) { std::lock_guard<std::mutex> lock(mtx); status_queue.push(std::move(status)); // 用move减少拷贝 } // sub_main调用:尝试取出一个状态(非阻塞) bool try_pop_status(YourStatusType& out_status) { std::lock_guard<std::mutex> lock(mtx); if (status_queue.empty()) { return false; } out_status = std::move(status_queue.front()); status_queue.pop(); return true; } }; // sub_main的核心逻辑 void sub_main(StatusNotifier& notifier) { while (/* 你的长期运行条件 */) { // 先处理你的主业务逻辑 do_your_main_work(); // 轮询状态:这里就是唯一的处理点 YourStatusType status; while (notifier.try_pop_status(status)) { // 一次性处理所有攒下来的状态 handle_status(status); } // 可选:加个短休眠,减少空转的CPU占用(反正你不需要极致快) std::this_thread::sleep_for(std::chrono::milliseconds(100)); } }
这个方案的好处就是简单易懂,几乎没有坑,线程安全也有保障,完全符合你的需求。
方案2:队列+条件变量(优化CPU占用)
如果你觉得纯轮询有点浪费CPU(虽然你说不需要极致快,但偶尔优化下也没坏处),可以给队列加个std::condition_variable,让sub_main在没状态的时候休眠,有状态进来再被唤醒。这样既不会空转,也能及时处理状态,而且还是单一位置处理:
#include <mutex> #include <queue> #include <condition_variable> #include <chrono> class StatusNotifier { private: std::mutex mtx; std::queue<YourStatusType> status_queue; std::condition_variable cv; public: void push_status(YourStatusType status) { std::lock_guard<std::mutex> lock(mtx); status_queue.push(std::move(status)); cv.notify_one(); // 通知sub_main有状态了 } // 带超时的等待:既不会一直堵着,也能及时处理状态 bool wait_for_status(YourStatusType& out_status, std::chrono::milliseconds timeout) { std::unique_lock<std::mutex> lock(mtx); // 等待超时,或者队列里有状态 if (cv.wait_for(lock, timeout, [this](){ return !status_queue.empty(); })) { out_status = std::move(status_queue.front()); status_queue.pop(); return true; } return false; } }; // sub_main里的逻辑调整 void sub_main(StatusNotifier& notifier) { while (/* 运行条件 */) { do_your_main_work(); YourStatusType status; // 等待100ms,期间有状态就处理,没状态就继续主逻辑 while (notifier.wait_for_status(status, std::chrono::milliseconds(100))) { handle_status(status); } } }
这个方案比纯轮询更高效,但复杂度稍微高一点,不过C++11的条件变量用法已经很成熟了,只要注意锁的释放逻辑就行。
为啥不推荐其他方案?
- 比如回调函数:要是其他线程直接调你的状态处理函数,那处理逻辑就跑到其他线程里了,不符合“单一位置处理”的要求,还容易搞出线程安全问题,绝对不推荐。
- 比如信号量:C++11没有原生信号量,自己封装的话反而麻烦,不如队列+锁/条件变量直观。
总结
如果追求简单好维护,直接用线程安全队列+轮询就够了,完全满足你的所有需求;如果想稍微优化下CPU占用,就选队列+条件变量的方案。你最开始想到的“带内部状态队列的对象工厂”其实就是这个思路的核心,只要把队列封装成可共享的对象,保证线程安全,就没问题啦!
内容的提问来源于stack exchange,提问作者PiotrK
相关产品推荐
相关产品推荐

