C/C++条件变量使用说明

C/C++条件变量使用说明

一、使用方法

C语言中,条件变量主要配合互斥锁,用于实现“生产者-消费者”模型,使用方法如下:
生产者:

  1. 获取互斥锁 pthread_mutex_lock
  2. 生产商品
  3. 通知消费者 pthread_cond_signal
  4. 释放互斥锁 pthread_mutex_unlock

消费者:

  1. 获取互斥锁 pthread_mutex_lock
  2. 判断是否存在可消费商品,是则执行3,否则等待生产者通知,直到存在商品 pthread_cond_wait
  3. 消费商品
  4. 释放互斥锁 pthread_mutex_unlock

二、原理分析

1、条件变量存在的意义

在“生产者-消费者”模型中,有两大需求:

  1. 保护临界资源“商品”。
  2. “商品”生产完成后,及时通知消费者。
    针对需求1,可以使用互斥锁,保证临界资源的安全;针对需求2,初始的想法是,是否可以复用需求1中的互斥锁呢,因为当消费者去获取锁时,如果该锁正被生产者占用,那么消费者线程将被挂起,随者生产者完成本次商品的生产释放锁,消费者线程就立刻被唤醒,似乎是可以满足需求的,流程变为如下所示:
    生产者:
  1. 获取互斥锁 pthread_mutex_lock
  2. 生产商品
  3. 通知消费者 pthread_cond_signal
  4. 释放互斥锁 pthread_mutex_unlock

消费者:

  1. 获取互斥锁 pthread_mutex_lock
  2. 判断是否存在可消费商品,是则执行3,否则等待生产者通知,直到存在商品 pthread_cond_wait
  3. 消费商品
  4. 释放互斥锁 pthread_mutex_unlock

通过简单分析,就可以得出,该方式存在巨大问题:在生产者未进行生产时,消费者每次都将无任何阻碍的获得锁,发现没有商品,又立刻释放锁,从而导致线程空转,极大占用CPU处理能力。
因此,需要引入一种机制,当消费者发现无商品可处理时,将自身挂起,当有新的商品产生时,立刻唤醒处理,由此,条件变量便产生了。

2、条件变量的本质

等待条件变量(pthread_cond_wait)可依次拆分为三个操作:释放互斥锁等待在条件变量上再次获取互斥锁。由此,可以理解消费者检查商品并等待的逻辑为:

while(没有商品?)
    pthread_cond_wait(mutex);

即判断如果没有商品,则释放互斥锁,等待在条件变量上;当生产者生产了商品后,消费者立刻被唤醒,又再次获取互斥锁,重复以上的逻辑。

三、举例说明

为了使代码更简练,使用c++进行举例,说明如何使用条件变量,实现“生产者-消费者”模型:

#include <iostream>
#include <thread>
#include <condition_variable>
#include <string>
#include <mutex>
#include <atomic>
#include <unistd.h>

using namespace std;

mutex m;
condition_variable cv;
atomic<bool> stop(false);
unsigned int products = 0;

void consumer_thead()
{
    while(!stop || products) {
        unique_lock<mutex> lk(m);
        cv.wait(lk, []{return products;});
        cout << "consumer thread is consuming product, remain " 
             << products << "\n";
        products--;
    }
}

void producer_thread()
{
    int total = 0;
    while(!stop) {
        m.lock();
        products += 2;
        total += 2;
        cout << "producer thread produced product, remain " 
             << products << " total " << total << endl;
        if (10 <= total) {
            cout << "will stop produce" << endl;
        	stop = true;
        }
        cv.notify_one();
        m.unlock();
        sleep(1);
    }
}

int main()
{
    thread consumer(consumer_thead);
    thread producer(producer_thread);

    consumer.join();
    producer.join();
    return 0;
}
posted @ 2020-04-25 21:25  chenyunf22  阅读(1284)  评论(0编辑  收藏  举报