std::condition_variable
在多线程编程中非常有用,特别是当需要在多个线程之间同步或等待某个条件成立时。下面是一个简单的 std::condition_variable
的应用举例,演示了如何使用它来实现一个生产者-消费者模型。
在这个例子中,我们将有一个生产者线程向一个队列中添加数据,而一个消费者线程从队列中取出数据。我们将使用 std::condition_variable
来在队列为空时让消费者线程等待,以及在队列非空时通知消费者线程。
#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
std::queue<int> data_queue;
std::mutex mtx;
std::condition_variable cv;
bool stop = false;
// 生产者线程
void producer() {
for (int i = 0; i < 10; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟耗时操作
std::lock_guard<std::mutex> lock(mtx);
data_queue.push(i);
std::cout << "Produced: " << i << std::endl;
cv.notify_one(); // 通知一个等待的线程
}
// 通知所有等待的线程,我们即将停止
{
std::lock_guard<std::mutex> lock(mtx);
stop = true;
}
cv.notify_all();
}
// 消费者线程
void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return !data_queue.empty() || stop; }); // 等待数据或停止信号
if (stop && data_queue.empty()) {
// 如果收到停止信号且队列为空,则退出循环
break;
}
int data = data_queue.front();
data_queue.pop();
lock.unlock(); // 在处理数据之前解锁,以避免长时间持有锁
std::cout << "Consumed: " << data << std::endl;
// ... 在这里处理数据 ...
}
}
int main() {
std::thread producer_thread(producer);
std::thread consumer_thread(consumer);
producer_thread.join();
consumer_thread.join();
return 0;
}
在这个例子中,生产者线程向 data_queue
中添加数据,并通过 cv.notify_one()
通知等待的消费者线程。消费者线程使用 cv.wait()
等待数据,直到队列非空或收到停止信号。当消费者线程被唤醒时,它会检查队列是否为空或是否收到停止信号,并据此决定是否继续处理数据或退出循环。
注意,我们在处理数据之前释放了互斥锁(通过 lock.unlock()
),以避免在处理数据期间长时间持有锁,从而允许其他线程访问队列。然而,在实际应用中,你需要确保在释放锁之后重新获取锁之前,你的代码是线程安全的。在这个例子中,由于我们只是简单地打印数据,所以没有问题。但在更复杂的场景中,你可能需要更复杂的同步机制来确保线程安全。
运行结果:
Produced: 0
Consumed: 0
Produced: 1
Consumed: 1
Produced: 2
Consumed: 2
Produced: 3
Consumed: 3
Produced: 4
Consumed: 4
Produced: 5
Consumed: 5
Produced: 6
Consumed: 6
Produced: 7
Consumed: 7
Produced: 8
Consumed: 8
Produced: 9
Consumed: 9