高阶开发基础——快速入门C++并发编程5 信号量的使用
目录
简单说说condition_variable
一个例子
简单说说condition_variable
condition_varaible是mutex的一个更加高阶的使用。它用来负责简化资源的请求和使用。或者说,他让多个线程对资源的使用变得有序。
一个代表性的例子就是我们的消费生产模型。假设有两个线程,一个线程负责生产数据,另一个线程负责消费数据。生产线程需要等到消费线程处理完数据后才能继续生产,而消费线程需要等到有数据时才能开始消费。
这时候就可以用 condition_variable
来实现:
-
等待条件:消费线程发现没有数据时,会调用
condition_variable
的wait()
函数进入等待状态,直到生产线程通知它有数据了。 -
通知条件:生产线程生产完数据后,调用
condition_variable
的notify_one()
或notify_all()
函数,告诉消费线程“数据准备好了,可以开始消费了”。
简单来说,condition_variable
就像是一个信号灯:
-
线程可以在这个信号灯前等待(
wait()
),直到其他线程发出信号(notify()
)。 -
当信号发出后,等待的线程就会被唤醒,继续执行。
它的核心作用是避免线程忙等待(不断检查条件是否成立),从而节省 CPU 资源。
一个例子
我们就对上面的例子进行编程
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <print>
#include <queue>
#include <thread>
std::mutex mtx;
std::queue<int> global_working_queue;
std::condition_variable global_con_var;
bool shell_stop = false;
void producer() {
for (int i = 0; i < 50; i++) {
{
std::unique_lock<std::mutex> locker(mtx);
global_working_queue.push(i);
global_con_var.notify_one();
std::print("we push {} into the task\n", i);
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
shell_stop = true;
}
void consumer() {
while (!shell_stop) {
std::unique_lock<std::mutex> locker(mtx);
// if the queue is empty, we need to wait
global_con_var.wait(locker, [](){return !global_working_queue.empty() || !shell_stop;});
if(global_working_queue.empty()){
continue;
}
int value = global_working_queue.front();
global_working_queue.pop();
std::print("Fetch the value in consumer {}\n", value);
}
}
int main() {
auto pro = std::thread(producer);
auto con = std::thread(consumer);
pro.join();
con.join();
}
在这个例子中,笔者让一个消费者源源不断的往里塞入数据。每当我们塞好了数据,就会通知我们的线程取出数据。进行消费。对于生产者,则是每一次准备处理数据的时候,先向条件变量请示一下,我可不可以进行处理。条件变量依据我们的判断条件,当我们的输入不是队列空的时候,就不需要等待,直接处理队列内数据(wait的判断条件要求的是当为真的适合不去等待,假的时候(也就是资源此时不可以被请求,你要等待)的时候休眠,直到消费者线程提醒你你要起来处理数据)