You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免工作线程因错过condition_variable通知而闲置,导致任务积压

解决条件变量通知丢失导致任务积压的问题

问题描述

我有若干工作线程等待队列中的任务。通常生产者调用produce函数后,会调用notify_one让工作线程解除阻塞并执行。但如果生产者生产任务时,没有线程在condition_variable上等待,此时notify_one不会产生任何作用。之后工作线程(消费者)调用wait时,会错过之前的通知,导致队列中已有任务,却要等到生产者再次调用notify才会处理,届时队列会积压两个任务。请问如何避免队列有任务等待,同时存在可用工作线程的情况?

原示例代码

struct ThreadPool
{
    static inline std::mutex mutex;
    static inline std::condition_variable condition_var;

    static inline int number_of_things_to_consume = 0;

    static void consume()
    {
        std::unique_lock lock{ mutex };

        /* 这里可能出现队列有任务但工作线程还在等待的情况
        - 因为生产者调用了notify_one但当时没有线程在等待 */
        condition_var.wait(lock, []() {return number_of_things_to_consume > 0; });

        /* 消费逻辑 */
    }

    static void produce()
    {
        std::unique_lock lock{ mutex };
        ++number_of_things_to_consume;
        condition_var.notify_one();
    }
};

解决方案

你其实不用太担心这个问题——因为代码里用的是带谓词的condition_variable::wait,它的工作机制已经从根源上避免了这种情况。

带谓词的wait等价于以下逻辑:

while (!pred()) {
    wait(lock);
}

也就是说,当消费者线程执行到wait时,会先检查谓词条件(这里是number_of_things_to_consume > 0):

  • 如果条件已经满足(比如生产者已经生产了任务),线程不会进入阻塞,直接跳过wait执行后续的消费逻辑;
  • 只有条件不满足时,才会释放锁并进入等待状态,等待生产者的通知。

所以哪怕生产者先调用了notify_one但当时没有线程等待,后续消费者线程到达wait时,会直接发现任务已经存在,不会傻等下一次通知。

如果要让逻辑更严谨、贴合实际场景,还可以做以下优化:

  • 用std::queue代替单纯的计数变量,存储实际任务,避免计数和任务数量不一致的问题;
  • 消费任务时,拿到任务后及时解锁,不要让锁长时间持有,提升并发效率。

优化后的代码示例

#include <mutex>
#include <condition_variable>
#include <queue>

struct ThreadPool
{
    static inline std::mutex mutex;
    static inline std::condition_variable condition_var;
    static inline std::queue<int> task_queue; // 用队列存储具体任务

    static void consume()
    {
        std::unique_lock lock{ mutex };

        // 先检查队列是否非空,非空直接执行消费,不进入等待
        condition_var.wait(lock, []() {return !task_queue.empty(); });

        // 取出任务
        int task = task_queue.front();
        task_queue.pop();
        lock.unlock(); // 提前解锁,避免处理任务时占用锁

        // 这里写任务处理逻辑...
    }

    static void produce(int task)
    {
        std::unique_lock lock{ mutex };
        task_queue.push(task);
        condition_var.notify_one();
    }
};

内容的提问来源于stack exchange,提问作者Zebrafish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 01:53:16