std::condition_variable 详解

std::condition_variable 是 C++ 标准库中的一个类,用于同步线程的执行。它通常与 std::unique_lock 或 std::lock_guard 配合使用,以及一个条件(通常是 std::condition_variable 的成员变量),以允许线程等待某个条件成立。

下面是 std::condition_variable 的主要功能和方法的详解:

  1. 构造函数

    • std::condition_variable():默认构造函数。
  2. 等待方法

    • void wait(std::unique_lock<std::mutex>& lock): 使当前线程阻塞,直到另一个线程调用 notify_one 或 notify_all。在等待期间,lock 会被自动释放,当线程被唤醒时,lock 会被重新锁定。
    • template< class Predicate > bool wait(std::unique_lock<std::mutex>& lock, Predicate pred): 除了等待通知外,还检查 pred 是否为 true。如果 pred 为 false,则线程会阻塞,直到 pred 为 true 或收到通知。
    • void wait_for(std::unique_lock<std::mutex>& lock, std::chrono::duration<Rep,Period> timeout): 与 wait 类似,但有一个超时时间。如果在超时时间内没有收到通知,则线程会停止阻塞。
    • template< class Rep, class Period, class Predicate > std::cv_status wait_for(std::unique_lock<std::mutex>& lock, std::chrono::duration<Rep,Period> timeout, Predicate pred): 结合了 wait_for 和带谓词的 wait 的功能。
    • void wait_until(std::unique_lock<std::mutex>& lock, std::chrono::time_point<Clock,Duration> timeout): 与 wait_for 类似,但使用时间点而不是持续时间作为超时。
    • template< class Clock, class Duration, class Predicate > std::cv_status wait_until(std::unique_lock<std::mutex>& lock, std::chrono::time_point<Clock,Duration> timeout, Predicate pred): 结合了 wait_until 和带谓词的 wait 的功能。
  3. 通知方法

    • void notify_one(): 唤醒等待在 std::condition_variable 上的一个线程(如果有的话)。
    • void notify_all(): 唤醒等待在 std::condition_variable 上的所有线程。

使用场景

假设你有多个线程,其中一个线程负责产生数据(生产者),而其他线程负责消费这些数据(消费者)。当生产者产生数据时,它可能会设置一个条件变量来通知消费者线程数据已经准备好。消费者线程则会在循环中等待这个条件变量,直到数据准备好。

#include <iostream>  
#include <thread>  
#include <mutex>  
#include <condition_variable>  
#include <queue>  
  
std::queue<int> dataQueue;  
std::mutex mtx;  
std::condition_variable condVar;  
  
void producer() {  
    for (int i = 0; i < 10; ++i) {  
        std::unique_lock<std::mutex> lock(mtx);  
        dataQueue.push(i);  
        lock.unlock();  
        condVar.notify_one();  
        std::this_thread::sleep_for(std::chrono::seconds(1));  
    }  
}  
  
void consumer() {  
    while (true) {  
        std::unique_lock<std::mutex> lock(mtx);  
        condVar.wait(lock, [] { return !dataQueue.empty(); });  
        int data = dataQueue.front();  
        dataQueue.pop();  
        lock.unlock();  
        std::cout << "Consumed: " << data << std::endl;  
    }  
}  
  
int main() {  
    std::thread prod(producer);  
    std::thread cons(consumer);  
  
    prod.join();  
    cons.detach();  
  
    return 0;  
}

在这个例子中,生产者线程将整数推入队列,并通过 notify_one 通知消费者线程。消费者线程则在一个循环中等待数据,直到数据队列不为空。注意,当调用 wait 时,锁会自动释放,当线程被唤醒时,锁会重新被锁定。这是为了避免死锁并确保线程安全。

举例说明`std::condition_variable`的使用场景

std::condition_variable 的使用场景通常涉及到多个线程之间的同步,特别是在生产者-消费者模型、任务队列、多线程资源共享等场景中。以下是几个具体的例子来说明 std::condition_variable 的使用场景:

1. 生产者-消费者模型

在生产者-消费者模型中,生产者线程生成数据项并将其放入缓冲区(如队列),而消费者线程从缓冲区中取出数据项进行处理。std::condition_variable 可以用来同步生产者和消费者线程,确保消费者线程不会在缓冲区为空时尝试读取数据,而生产者线程也不会在缓冲区满时尝试写入数据。

#include <iostream>  
#include <thread>  
#include <queue>  
#include <mutex>  
#include <condition_variable>  
  
std::queue<int> queue;  
std::mutex mtx;  
std::condition_variable cond_var;  
  
void producer() {  
    for (int i = 0; i < 10; ++i) {  
        std::unique_lock<std::mutex> lock(mtx);  
        queue.push(i);  
        lock.unlock();  
        cond_var.notify_one();  // 通知一个等待的消费者线程  
    }  
}  
  
void consumer() {  
    while (true) {  
        std::unique_lock<std::mutex> lock(mtx);  
        cond_var.wait(lock, [] { return !queue.empty(); });  // 等待队列非空  
        int value = queue.front();  
        queue.pop();  
        lock.unlock();  
        std::cout << "Consumed: " << value << std::endl;  
    }  
}  
  
int main() {  
    std::thread producer_thread(producer);  
    std::thread consumer_thread(consumer);  
  
    producer_thread.join();  
    consumer_thread.detach();  // 消费者线程通常持续运行  
  
    return 0;  
}

2. 任务队列

在多线程环境中,任务队列通常用于分配工作给不同的线程。当新的任务添加到队列时,需要通知等待任务的线程。std::condition_variable 可以用来实现这一通知机制。

#include <iostream>  
#include <thread>  
#include <vector>  
#include <queue>  
#include <mutex>  
#include <condition_variable>  
#include <functional>  
  
std::queue<std::function<void()>> task_queue;  
std::mutex mtx;  
std::condition_variable cond_var;  
bool stop = false;  
  
void worker_thread() {  
    while (!stop) {  
        std::unique_lock<std::mutex> lock(mtx);  
        cond_var.wait(lock, [] { return !task_queue.empty() || stop; });  // 等待任务或停止信号  
        if (stop && task_queue.empty()) {  
            break;  // 如果收到停止信号且队列为空,则退出循环  
        }  
        std::function<void()> task = std::move(task_queue.front());  
        task_queue.pop();  
        lock.unlock();  
        task();  // 执行任务  
    }  
}  
  
int main() {  
    std::vector<std::thread> workers;  
    for (int i = 0; i < 4; ++i) {  // 创建四个工作线程  
        workers.emplace_back(worker_thread);  
    }  
  
    // 添加任务到队列  
    {  
        std::lock_guard<std::mutex> lock(mtx);  
        task_queue.push([] { std::cout << "Task 1 executed\n"; });  
        task_queue.push([] { std::cout << "Task 2 executed\n"; });  
        // ... 添加更多任务 ...  
    }  
    cond_var.notify_all();  // 通知所有等待的线程有任务可用  
  
    // ... 在某个时刻,我们想要停止所有工作线程 ...  
    {  
        std::lock_guard<std::mutex> lock(mtx);  
        stop = true;  
    }  
    cond_var.notify_all();  // 通知所有线程停止工作  
  
    for (auto& worker : workers) {  
        worker.join();  
    }  
  
    return 0;  
}

3. 多线程资源共享

当多个线程需要访问和修改共享资源时,std::condition_variable 可以用来确保资源在修改时不会被其他线程访问,以及在资源准备好时被正确通知。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值