[c++多线程并发 基础入门] 1.3条件变量condition

[c++多线程并发 基础入门] 1.3条件变量condition,第1张

1.无条件变量时
#include 
#include 
#include 
#include 
#include 

std::mutex mtx;
std::deque<int> q;

//producer
void task1()
{
    int i = 0;
    
    while(true)
    {
        std::unique_lock<std::mutex> lock(mtx);
        q.push_back(i);
        //this thread delay 10ms
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        
        if(i < 99)
        {
            i++;
        }
        else
        {
            i = 0;
        }
    }
}

//consumer
void task2()
{
    int data = 0;
    
    while(true)
    {
        std::unique_lock<std::mutex> lock(mtx);
        
        if(!q.empty())
        {
            data = q.front();
            q.pop_front();
            std::cout<< "get value from que: "<<data<<std::endl;
        }
     
        //this thread delay 10ms
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    
}

int main(int argc, const char * argv[]) 
{
    std::thread t1(task1);
    std::thread t2(task2);
    
    t1.join();
    t2.join();
    
    return 0;
}

使用延时std::this_thread::sleep_for(std::chrono::milliseconds(10)); 表示当前线程休眠一段时间,休眠期间不与其他线程竞争CPU,根据线程需求,等待若干时间。

延时过长,消费者线程不能及时的从队列里面取数据
延时过短,对CPU的占用率不能很大缓解

2条件变量

例子:

#include 
#include 
#include 
#include 
#include 
#include 

std::mutex mtx;
std::deque<int> q;
std::condition_variable cv;

//producer
void task1()
{
    int i = 0;
    
    while(true)
    {
        std::unique_lock<std::mutex> lock(mtx);
        
        q.push_back(i);
        cv.notify_one();
        
        if(i < 20)
        {
            i++;
        }
        else
        {
            i = 0;
        }
    }
}

//consumer
void task2()
{
    int data = 0;
    
    while(true)
    {
        std::unique_lock<std::mutex> lock(mtx);
        
        if(q.empty())
        {
            cv.wait(lock);
            //cv.wait(lock) 相当于下面两行
            //lock.unlock();
            //cv.wait();
        }
        
        if(!q.empty())
        {
            data = q.front();
            q.pop_front();
            std::cout<< "get value from que: "<<data<<std::endl;
        }
    } 
}


int main(int argc, const char * argv[]) {

    std::thread t1(task1);
    std::thread t2(task2);

    t1.join();
    t2.join();
    
    return 0;
}

macOS xcode 运行结果:
get value from que: 0
get value from que: 1
get value from que: 2
get value from que: 3
get value from que: 4
get value from que: 5
get value from que: 6
get value from que: 7
get value from que: 8
get value from que: 9
get value from que: 10
get value from que: 11
get value from que: 12
get value from que: 13
get value from que: 14
get value from que: 15
get value from que: 16
get value from que: 17
get value from que: 18
get value from que: 19
get value from que: 20
get value from que: 0
get value from que: 1
get value from que: 2
get value from que: 3
get value from que: 4
get value from que: 5
get value from que: 6
get value from que: 7
get value from que: 8
get value from que: 9
get value from que: 10
get value from que: 11
get value from que: 12
get value from que: 13
get value from que: 14
get value from que: 15
get value from que: 16
get value from que: 17
get value from que: 18
get value from que: 19
get value from que: 20
get value from que: 0
get value from que: 1
get value from que: 2
get value from que: 3
get value from que: 4
get value from que: 5
get value from que: 6
get value from que: 7
get value from que: 8
get value from que: 9
get value from que: 10
get value from que: 11
get value from que: 12
get value from que: 13
get value from que: 14
get value from que: 15
get value from que: 16
get value from que: 17
get value from que: 18
get value from que: 19
get value from que: 20
get value from que: 0
get value from que: 1
get value from que: 2

3虚假唤醒
#include 
#include 
#include 
#include 
#include 
#include 

std::mutex mtx;
std::deque<int> q;
std::condition_variable cv;

//producer
void task1()
{
    int i = 0;
    
    while(true)
    {
        std::unique_lock<std::mutex> lock(mtx);
        
        q.push_back(i);
        cv.notify_one();
        
        if(i < 2000000000)
        {
            i++;
        }
        else
        {
            i = 0;
        }
    }
}

//consumer1
void task2()
{
    int data = 0;
    
    while(true)
    {
        std::unique_lock<std::mutex> lock(mtx);
        
        if(q.empty())
        {
            cv.wait(lock);//意思是下面两句,解锁再等待
            //lock.unlock();
            //cv.wait();
        }
        
        data = q.front();
        q.pop_front();
        std::cout<< "get value from que: "<<data<<std::endl;
    }
    
}

//consumer2
void task3()
{
    int data = 0;
    
    while(true)
    {
        std::unique_lock<std::mutex> lock(mtx);
        
        if(q.empty())
        {
            cv.wait(lock);//意思是下面两句,解锁再等待
            //lock.unlock();
            //cv.wait();
        }
        
        data = q.front();
        q.pop_front();
        std::cout<< "get value from que: "<<data<<std::endl;
    }
}

int main(int argc, const char * argv[]) {

    std::thread t1(task1);
    std::thread t2(task2);
    std::thread t3(task2);
    
    t1.join();
    t2.join();
    t3.join();
    
    return 0;
}

以上可能造成虚假唤醒,当生产者q.push_back(i);时:消费者1判断队列不为空 后取出队列头的元素并移除,生产者notify_one后通知消费者2,消费者2从wait中唤醒,然后又去取队列头部数据,此时队列头部数据已经被消费者1移除了,报错,这就是虚假唤醒

解决方法:
把消费者1, 消费者2中的 if改成while

 if(q.empty())
 {
     cv.wait(lock);//意思是下面两句,解锁再等待
     //lock.unlock();
     //cv.wait();
 }

改成:

 while(q.empty())
 {
     cv.wait(lock);//意思是下面两句,解锁再等待
     //lock.unlock();
     //cv.wait();
 }

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1325204.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-12
下一篇2022-06-12

发表评论

登录后才能评论

评论列表(0条)

    保存