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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM