生產者和消費者模型

一:條件變量:
我們知道多線程訪問時會出現衝突的問題,爲了解決這個問題我們引入互斥鎖的概念,即多個線程同時訪問理解資源時,獲得鎖多線程可以完成”讀-修改-寫”操作,然後釋放鎖給其他線程.沒有獲得鎖的線程只能掛起等待.
與互斥鎖不同,條件變量時掛起等待而不是上鎖,條件變量用來自動阻塞一個線程,直到某特殊情況的發生,通常條件變量和互斥鎖同時使用.
原理:條件變量是利用線程間共享的全局變量進行同步的一種機制,主要包括兩個動作:一個線程等待”條件變量的條件成立”而掛起;另一個線程”條件成立”
條件的檢測是在互斥鎖的保護條件下進行的,如果一個條件爲假,一個線程自動阻塞,並釋放等待狀態的互斥鎖,如果一個線程改變了條件,它發關聯的條件變量,喚醒一個或多個等待的線程,重新獲得互斥鎖,然後重新評價條件.如果樑金成共享讀寫的內存,條件變量可以實現這兩個進程間的線程同步
初始化和釋放函數:
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
cond一般用宏來進行初始化.

int pthread_cond_destroy(pthread_cond_t *cond)
這裏寫圖片描述
返回值:成功返回0,失敗返回錯誤號
和Mutes的初始化和銷燬類似,ptread_cond_init函數初始化一個條件變量,attr參數爲NULL,則表示缺省屬性,ptread_cond_destory函數銷燬一個條件變量,如果條件變量是靜態的,可以用宏定義初始化,等同於初始化函數,並且attr參數爲NULL;
條件變量還有以下函數:
這裏寫圖片描述
返回值:成功返回0,失敗返回錯誤號
可見,一個條件變量總是和一個Mutex搭配使用,一個線程可以調用pthread_cond_wait在一個條件變量上阻塞等待,這個函數做以下三步操作:
1:釋放Mutex
2:阻塞等待
3:當被喚醒時,重新獲得Mutex並返回.
pthread_cond_timedwait函數還有一個額外的參數可以設定等待超時,如果達到abstime所指指定的時刻仍然沒有別的線程來喚醒當前線程,後返回ETIMEDOUT.一個線程可以調用pthead_cond_signal喚醒在某個Condition Variable上等待的另一個線程,也可以調用pthread_cond_broadcast喚醒在這個Condition Veriable上等待的所有線程.
這裏寫圖片描述
一個線程可以調用pthread_cond_signal喚醒在某個條件變量上等待的另一個線程,也可以調用
pthread_cond_broadcast喚醒在這個條件變量上等待的所有線程.
生產者消費者問題是同步問題中的一種常見情況,生產者消費者問題 .也稱有限緩衝問題,是一個多線程同步問題.在實際運行過程中,生產者的主要作用是生成一定數量的數據放到緩衝區中,然後重複此過程,與此同時,消費者也在緩衝區消耗 這些數據.問題的關鍵是保證生產者不會在緩衝區滿時加入數據,消費者不會在緩衝區空時消耗數據.
二:生產者消費者模型
生產者和生產者之間爲互斥關係
消費者和消費者之間爲互斥關係
生產者與消費者之間既有同步又有互斥關係
這裏寫圖片描述
解耦
假設生產者和消費者分別是兩個類,如果讓生產者直接調用消費者的某個方法,那麼生產者對於消費者就會產生依賴(也就是耦合),將來如何是消費者代碼發生變化,可能會影響生產者,如果都是依賴這個緩衝區,耦合就會相應的降低
支持併發:
生產者直接調用消費者的某個方法,還有另一個弊端.由於函數調用時同步的,在消費者的方法沒有返回之前,生產者只好在一邊等待,但是如果消費者處理數據很慢,生產者就會浪費很多時間.
使用生產者/消費者模式之後,生產者和消費者可以是兩個獨立的併發主體,(常見的併發類型有進程和線程兩種),生產者生產的數據放到緩衝區,就可以繼續生產,基本不依賴消費者的處理速度.
支持忙閒不均
換衝區的另外一個好處是,如果生產的數據快的時候,消費者來不及處理,未處理的數據可以暫時存在緩衝區,等生產者的生產速度降低,消費者再慢慢處理數據.
基於單鏈表的生產者消費者模型:

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
typedef struct SlistNode
{
 struct SlistNode*next;
    int _data;
}Slist;

//初始化
void Init(Slist*head)
{
    if(head!=NULL)
    {
        head->next =NULL;
        head->_data = 0;
    }
}
Slist*head =NULL;
//靜態創建
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t producter = PTHREAD_COND_INITIALIZER;
//消費者
void* consumer(void *arg)
{
    Slist *p = NULL;
    while(1)
    {
        pthread_mutex_lock(&lock);//加鎖
        while(head ==NULL)
        {
        //條件不滿足,阻塞式等待             
        pthread_cond_wait(&producter,&lock);

        }
        //尾刪
        p = head;
        head =head->next;
        p->next = NULL;
        pthread_mutex_unlock(&lock);//釋放鎖
        printf("Consumer success :_data is %d\n",p->_data);
 free(p);
p = NULL;
    }
    return NULL;
}
//生產者
void *product(void *arg)
{

    while(1)
    {
        sleep(rand()%2);
        Slist*p = malloc(sizeof(Slist));
        pthread_mutex_lock(&lock);
        Init(p);
        p->_data = rand()%1000;
        //頭插
        p->next = head;
        head= p;
        pthread_mutex_unlock(&lock);
        printf("call consumer,product success,data is:%d\n",p->_data);
        pthread_cond_signal(&producter);
    }
}
int main()
{
    pthread_t t_product;
    pthread_t t_consumer;

    pthread_create(&t_product,NULL,product,NULL);//創建線程
    pthread_create(&t_consumer,NULL,consumer,NULL);//創建線程
    pthread_join(t_product,NULL);//線程等待
    pthread_join(t_consumer,NULL);

    return 0;
}

這裏寫圖片描述

發佈了113 篇原創文章 · 獲贊 62 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章