1.3-多线程控制的另一种姿势-条件变量(condition_variable), 信号量(semaphore)
这篇文章串联了 C++11 条件变量与 C++20 信号量两个同步原语,重点解释它们解决的问题、典型误区和适用场景。条件变量为何必要仅靠互斥锁实现生产者-消费者时,消费者线程容易在空队列上反复抢锁,浪费 CPU。条件变量可以在“无数据”时阻塞消费者,在“有数据”时由生产者主动通知唤醒。文章通过改造前后代码对比,说明了从…
条件变量(C++11)为什么要引入条件变量 我们先来看看一个由互斥量加锁构成的生产者消费者模型:// // Created by Alone on 2022-3-27. // #include <iostream> #include <mutex> #include <deque> #include <thread> std::mutex mtx; std::deque<int> q; // producer void task1(){ int i = 0; while (1){ std::unique_lock<std::mutex> lock(mtx); //std::this_thread::sleep_for(std::chrono::milliseconds(10)); q.push_back(i); if (i < 9999999) { i++; }else { i = 0; } } } // consumer void task2(){ int data = 0; while (1) { std::unique_lock<std::mutex> lock(mtx); if(!q.empty()){ data = q.front(); q.pop_front(); std::cout<<"Get value from que task2:"<<data<<std::endl; } } } void task3(){ int data = 0; while (1) { std::unique_lock<std::mutex> lock(mtx); if (!q.empty()) { data = q.front(); q.pop_front(); std::cout<<"Get value from que task3:"<<data<<std::endl; } } } int main() { std::thread t1(task1); std::thread t2(task2); std::thread t3(task3); t1.join(); t2.join(); t3.join(); return 0; } 以上代码,由于直接的while(1)循环会导致cpu资源占用的非常厉害,我们可以通过延时sleep_for来进行优化,但这个延时的时间我们并不好控制! 我们这个生产者、消费者线程,想要实现的愿景就是,当生成者生产出资源后,我们能够及时的唤醒消费者线程,让其获取资源。 但如果是简单的对生产者和消费者进行加锁来实现这一过程,可能中间会有很多过程是在消费者拿到锁后,发现生产者并没有生产出资源,而这个过程很明显就是一个无用功,那么有没有一种方式能够让生产者生产出资源后,立马通知消费者线程来读取,且在没有资源的时候,消费者线程能够阻塞让出cpu时间片呢?实现这个需求有很多种方法,而条件变量就是其中的一种!条件变量的用法 从C++11起,标准库开始引入条件变量。 它的成员函数也不复杂,就下面这些: 更多详细描述 void wait (unique_lock<mutex>& lck); 这是非模板成员函数类型,接收一个unique_lock,调用后,会帮你unlock,并且线程陷入等待状态,直到被调用notify唤醒。 有关notify的成员函数也就这两个:notify_one和notify_all。 顾名思义,随机唤醒一个,和唤醒全部处于等待被唤醒的线程。 我们再利用新学的条件变量改造下前面的代码如下:#include <iostream> #include <mutex> #include <deque> #include <thread> #include <condition_variable> std::mutex mtx; std::deque<int> q; std::condition_variable cv; // producer void task1(){ int i = 0; while (1){ std::unique_lock<std::mutex> lock(mtx); q.push_back(i); cv.notify_one(); if (i < 9999999) { i++; }else { i = 0; } } } // consumer void task2(){ int data = 0; while (1) { std::unique_lock<std::mutex> lock(mtx); if(q.empty()) { cv.wait(lock); } data = q.front(); q.pop_front(); std::cout<<"Get value from…
正在初始化 WebAssembly 引擎…
首次编译原生模块可能需要数秒
就绪后,页面交互将以接近原生的速度运行