#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
std::mutex mtx;
std::condition_variable cv_producer, cv_consumer;
std::queue<int> buffer;
const int MAX_BUFFER_SIZE = 5;
void producer() {
for (int i = 0; i < 10; ++i) {
std::unique_lock<std::mutex> lock(mtx);
cv_consumer.wait(lock, [] { return buffer.size() < MAX_BUFFER_SIZE; });//满足 cv_consumer唤醒不阻塞 往下执行 锁定
// 生产者向缓冲区添加数据
buffer.push(i);
std::cout << "Produced: " << i << std::endl;
lock.unlock();
cv_producer.notify_one(); // 唤醒等待在生产者条件变量上的线程
}
}
void consumer() {
for (int i = 0; i < 10; ++i) {
std::unique_lock<std::mutex> lock(mtx);
cv_producer.wait(lock, [] { return !buffer.empty(); });
// 消费者从缓冲区取走数据
int data = buffer.front();
buffer.pop();
std::cout << "Consumed: " << data << std::endl;
lock.unlock();
cv_consumer.notify_one(); // 唤醒等待在消费者条件变量上的线程
}
}
int main() {
std::thread producer_thread(producer);
std::thread consumer_thread(consumer);
producer_thread.join();
consumer_thread.join();
return 0;
}
cv_consumer.wait(lock, [] { return buffer.size() < MAX_BUFFER_SIZE; });
解释如下:
-
cv_consumer.wait(lock, predicate)
是一个等待函数,它会阻塞当前线程,直到被通知(通过notify_one
或notify_all
)或超时,或者通过predicate
判断为真。 -
lock
是一个std::unique_lock
对象,用于锁定互斥量。在wait
调用期间,互斥量会被释放,以允许其他线程访问被保护的共享资源。 -
predicate
是一个用于判断是否满足条件的函数。在这里,lambda 表达式[] { return buffer.size() < MAX_BUFFER_SIZE; }
用于定义一个判断条件:缓冲区的大小是否小于最大缓冲区大小MAX_BUFFER_SIZE
。
所以,cv_consumer.wait
会等待直到条件 buffer.size() < MAX_BUFFER_SIZE
为真,即缓冲区不满时才唤醒。一旦被唤醒,它会重新锁定互斥量,允许线程继续执行后续的操作。
在生产者-消费者问题中,这样的设计可以确保生产者在缓冲区不满时执行生产操作,而消费者在缓冲区非空时执行消费操作,从而实现线程的同步。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool condition = false;
void producer() {
std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟生产过程
{
std::lock_guard<std::mutex> lock(mtx);
condition = true;
}
cv.notify_one(); // 通知消费者线程条件已满足
}
void consumer() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return condition; }); // 等待条件变量满足
std::cout << "Consumer: Received signal, consuming resources." << std::endl;
}
int main() {
std::thread producer_thread(producer);
std::thread consumer_thread(consumer);
producer_thread.join();
consumer_thread.join();
return 0;
}
std::lock_guard:
std::lock_guard 是一种简单的锁管理器,它在构造时立即锁定互斥锁,并在析构时自动释放锁。由于其自动化的特性,适用于那些只需要在作用域内锁定和解锁的情况。
在生产者线程的上下文中,当需要在一段代码块内保护共享资源时,使用 std::lock_guard 是简单而直接的选择。
std::unique_lock:
std::unique_lock 提供了更大的灵活性,它允许延迟锁定和解锁,并且可以手动控制锁定和解锁的时机。这使得 std::unique_lock 更适合一些需要更复杂锁定策略的场景,例如条件变量的使用。
在消费者线程的上下文中,当需要等待条件变量的发生时,使用 std::unique_lock 是更合适的选择,因为它可以方便地与条件变量配合使用,并提供了更灵活的锁定和解锁操作。
cv.wait(lock, []{ return condition; });:这行代码调用了条件变量 cv 的 wait 方法,它需要两个参数。第一个参数是 lock,它是一个 std::unique_lock<std::mutex> 对象,用于锁定互斥锁。第二个参数是一个可调用对象(通常是 Lambda 表达式),用于检查条件是否满足。
[]{ return condition; }:这是一个 Lambda 表达式,它用于检查条件是否满足。Lambda 表达式返回一个 bool 类型的值,表示条件是否满足。在这个例子中,Lambda 表达式返回 condition 的值,即检查条件变量 condition 是否为 true。
cv.wait(lock, []{ return condition; });:这行代码的作用是:如果条件 condition 不满足(即返回 false),则当前线程会被阻塞,同时释放 lock 对象所锁定的互斥锁。当其他线程修改了条件变量 condition 的值并调用了 cv.notify_one() 或 cv.notify_all() 时,当前线程会被唤醒,并尝试重新获取 lock 对象所锁定的互斥锁。如果条件 condition 满足(即返回 true),则当前线程不会被阻塞,继续执行后续代码。
总之,这段代码的作用是让当前线程在条件变量 condition 满足之前等待,并释放互斥锁以允许其他线程修改共享状态。