C++多线程std::condition_variable的使用,凭借条件变量等待条件成立

   std::condition_variable 是 C++ 标准库 <condition_variable> 头文件中提供的一个用于线程间同步的工具,它允许线程在某个条件满足时被唤醒。通常与 std::mutex 或 std::unique_lock 配合使用,在多线程编程中非常有用,比如实现生产者 - 消费者模型等场景。下面将从基本概念、工作原理、常用方法、应用场景和示例代码等方面详细介绍 std::condition_variable

基本概念

   std::condition_variable 本质上是一个同步原语,它提供了一种机制,让线程可以阻塞自己,直到另一个线程通知它某个条件已经满足。当一个线程等待条件变量时,它会释放持有的互斥锁,进入阻塞状态;当其他线程通知条件变量时,等待的线程会被唤醒,并尝试重新获取互斥锁。

工作原理

  1. 等待操作:当一个线程调用 std::condition_variable 的 wait 方法时,它会自动释放当前持有的互斥锁,并进入阻塞状态。此时,其他线程可以获取该互斥锁并修改共享状态。
  2. 通知操作:当另一个线程修改了共享状态,并且满足了某个条件时,它可以调用 std::condition_variable 的 notify_one 或 notify_all 方法。notify_one 会唤醒一个等待在该条件变量上的线程,而 notify_all 会唤醒所有等待在该条件变量上的线程。
  3. 重新锁定:被唤醒的线程会尝试重新获取之前释放的互斥锁,一旦获取成功,它会继续执行后续的代码。

常用方法

  • wait 系列方法
    • void wait( std::unique_lock<std::mutex>& lock );:阻塞当前线程,直到收到通知。调用该方法时,线程会自动释放 lock 持有的互斥锁,并进入等待状态;当收到通知并重新获取互斥锁后,线程会继续执行。
    • template< class Predicate > void wait( std::unique_lock<std::mutex>& lock, Predicate pred );:阻塞当前线程,直到收到通知且 pred 条件为 true。该方法会在每次被唤醒时检查 pred 的返回值,如果为 false 则继续等待。
  • notify 系列方法
    • void notify_one();:唤醒一个等待在该条件变量上的线程。如果没有线程在等待,则该调用没有效果。
    • void notify_all();:唤醒所有等待在该条件变量上的线程。

应用场景

  • 生产者 - 消费者模型:生产者线程生产数据并放入缓冲区,消费者线程从缓冲区取出数据进行处理。当缓冲区为空时,消费者线程可以等待条件变量;当生产者线程放入数据后,通知消费者线程。
  • 多线程任务同步:在某些场景下,一个线程需要等待其他线程完成特定任务后才能继续执行,此时可以使用条件变量进行同步。

示例代码(生产者 - 消费者模型)

#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>

std::queue<int> buffer;
std::mutex mtx;
std::condition_variable notFull;
std::condition_variable notEmpty;
const int MAX_SIZE = 5;

// 生产者线程函数
void producer() {
    for (int i = 0; i < 10; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        // 等待缓冲区不满
        notFull.wait(lock, [] { return buffer.size() < MAX_SIZE; });

        buffer.push(i);
        std::cout << "Produced: " << i << std::endl;

        // 通知消费者缓冲区非空
        notEmpty.notify_one();
    }
}

// 消费者线程函数
void consumer() {
    for (int i = 0; i < 10; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        // 等待缓冲区非空
        notEmpty.wait(lock, [] { return!buffer.empty(); });

        int value = buffer.front();
        buffer.pop();
        std::cout << "Consumed: " << value << std::endl;

        // 通知生产者缓冲区不满
        notFull.notify_one();
    }
}

int main() {
    std::thread producerThread(producer);
    std::thread consumerThread(consumer);

    producerThread.join();
    consumerThread.join();

    return 0;
}

        通过使用 std::condition_variable,实现了生产者和消费者线程之间的同步,确保了在缓冲区满时生产者线程等待,在缓冲区空时消费者线程等待。

`std::condition_variable` 是 C++ 标准库中用于线程同步的工具,定义在 `<condition_variable>` 头文件中,提供了 `wait`、`notify_one` 和 `notify_all` 等成员函数,主要用于让个线程等待某个条件成立,另个线程通知条件变化,以下是些常见的使用场景: #### 生产者 - 消费者模型 在生产者 - 消费者模型中,生产者线程负责生产数据,消费者线程负责消费数据。当缓冲区为空时,消费者线程需要等待;当缓冲区满时,生产者线程需要等待。`std::condition_variable` 可以用来实现这种等待和通知机制。 ```cpp #include <iostream> #include <queue> #include <thread> #include <mutex> #include <condition_variable> std::queue<int> buffer; std::mutex mtx; std::condition_variable not_full, not_empty; const int MAX_SIZE = 10; // 生产者线程函数 void producer() { for (int i = 0; i < 20; ++i) { std::unique_lock<std::mutex> lock(mtx); // 等待缓冲区不满 not_full.wait(lock, []{ return buffer.size() < MAX_SIZE; }); buffer.push(i); std::cout << "Produced: " << i << std::endl; // 通知消费者缓冲区非空 not_empty.notify_one(); } } // 消费者线程函数 void consumer() { for (int i = 0; i < 20; ++i) { std::unique_lock<std::mutex> lock(mtx); // 等待缓冲区非空 not_empty.wait(lock, []{ return !buffer.empty(); }); int item = buffer.front(); buffer.pop(); std::cout << "Consumed: " << item << std::endl; // 通知生产者缓冲区不满 not_full.notify_one(); } } int main() { std::thread t1(producer); std::thread t2(consumer); t1.join(); t2.join(); return 0; } ``` #### 线程池 在线程池中,当任务队列为空时,工作线程需要等待新任务的到来;当有新任务添加到队列时,需要通知个或多个工作线程开始工作。`std::condition_variable` 可以用来实现这种等待和通知机制。 ```cpp #include <iostream> #include <queue> #include <thread> #include <mutex> #include <condition_variable> #include <functional> #include <vector> class ThreadPool { public: ThreadPool(size_t numThreads) : stop(false) { for (size_t i = 0; i < numThreads; ++i) { threads.emplace_back([this] { while (true) { std::function<void()> task; { std::unique_lock<std::mutex> lock(this->mtx); // 等待任务队列非空或线程池停止 this->cv.wait(lock, [this] { return this->stop || !this->tasks.empty(); }); if (this->stop && this->tasks.empty()) return; task = std::move(this->tasks.front()); this->tasks.pop(); } task(); } }); } } ~ThreadPool() { { std::unique_lock<std::mutex> lock(mtx); stop = true; } cv.notify_all(); for (std::thread &thread : threads) { thread.join(); } } template<class F> void enqueue(F&& f) { { std::unique_lock<std::mutex> lock(mtx); if (stop) throw std::runtime_error("enqueue on stopped ThreadPool"); tasks.emplace(std::forward<F>(f)); } cv.notify_one(); } private: std::vector<std::thread> threads; std::queue<std::function<void()>> tasks; std::mutex mtx; std::condition_variable cv; bool stop; }; // 示例任务函数 void task() { std::cout << "Task is running." << std::endl; } int main() { ThreadPool pool(4); for (int i = 0; i < 10; ++i) { pool.enqueue(task); } return 0; } ``` #### 资源分配 在多线程程序中,当多个线程需要竞争使用某个资源时,可以使用 `std::condition_variable` 来实现资源的分配和释放。当资源可用时,通知等待的线程;当资源被占用时,线程需要等待。 ```cpp #include <iostream> #include <thread> #include <mutex> #include <condition_variable> bool resource_available = false; std::mutex mtx; std::condition_variable cv; // 使用资源的线程函数 void use_resource() { std::unique_lock<std::mutex> lock(mtx); // 等待资源可用 cv.wait(lock, []{ return resource_available; }); std::cout << "Resource is being used." << std::endl; resource_available = false; // 释放资源 cv.notify_one(); } // 释放资源的线程函数 void release_resource() { std::unique_lock<std::mutex> lock(mtx); resource_available = true; std::cout << "Resource is released." << std::endl; // 通知等待的线程 cv.notify_one(); } int main() { std::thread t1(use_resource); std::thread t2(release_resource); t1.join(); t2.join(); return 0; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摸鱼儿v

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值