如何等待另一个线程完成下一次循环迭代?
实现方案
核心实现代码
首先补充全局同步变量,然后实现目标函数:
#include <atomic> #include <chrono> #include <thread> #include <condition_variable> #include <mutex> // 新增同步变量 std::condition_variable cv; std::mutex cv_mutex; std::atomic<unsigned long> iteration_count = 0; void notify_any_waiting_threads() { // 递增迭代计数器,确保内存可见性 iteration_count.fetch_add(1, std::memory_order_release); // 通知所有等待的线程 cv.notify_all(); } void wait_for_worker_thread_iteration() { std::unique_lock<std::mutex> lock(cv_mutex); // 记录当前迭代次数 const auto target_iteration = iteration_count.load(std::memory_order_acquire); // 等待直到迭代次数发生变化(避免虚假唤醒) cv.wait(lock, [target_iteration] { return iteration_count.load(std::memory_order_acquire) != target_iteration; }); } // 原有代码保持不变 void do_work() { std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟耗时工作 } std::atomic_bool kill_worker_thread = false; std::atomic_bool worker_should_be_idle = false; void worker_thread_function() { while (!kill_worker_thread) { if (worker_should_be_idle) { std::this_thread::sleep_for(std::chrono::seconds(1)); // 空闲时休眠避免空转 } else { do_work(); } notify_any_waiting_threads(); } } void observer_thread_function() { worker_should_be_idle = true; wait_for_worker_thread_iteration(); // 此时可确保worker线程后续迭代都会进入idle状态,不再执行do_work() } int main() { std::thread worker_thread(worker_thread_function); std::this_thread::sleep_for(std::chrono::milliseconds(1800)); // 模拟观察者线程延迟启动 std::thread observer_thread_1(observer_thread_function); // 清理逻辑 observer_thread_1.join(); kill_worker_thread = true; worker_thread.join(); }
关键细节说明
- 条件变量的合理性:每次迭代完成后调用
notify_all()完全合法,这正是条件变量的核心用途——在状态变化时唤醒等待线程,这里的“迭代完成”就是明确的触发点。 - 谓词的作用:
wait()的谓词用于规避虚假唤醒,即使线程被唤醒,也要确认迭代次数确实更新,才会退出等待逻辑。 - 内存序优化:
memory_order_release和memory_order_acquire确保worker线程对iteration_count的修改能被等待线程立即感知,避免内存可见性问题。
替代同步原语分析
std::latch/std::barrier:这类原语适用于一次性或固定次数的同步场景,但你的需求是支持多次等待“下一次迭代”,条件变量的灵活性更匹配。std::atomic_flag:仅能实现简单信号量功能,无法跟踪迭代次数,无法区分“是否为目标迭代”,可靠性和直观性不如条件变量。
关于“等待下一次迭代”是否为反模式
这不是反模式,而是非常常见的线程同步需求:
- 典型场景包括:等待工作线程完成单次任务后读取结果、同步线程间状态切换(如你的场景中确认worker进入idle状态)、批量任务的进度同步等。
- 只要同步逻辑清晰、避免死锁和竞态,这种设计完全合理。
内容的提问来源于stack exchange,提问作者oliver
相关产品推荐
相关产品推荐

