Linux--生产者与消费者
http://blog.csdn.net/gebushuaidanhenhuai/article/details/74011636
基本概念
提到生產(chǎn)者和消費(fèi)者,我們最有可能想到的是商店賣(mài)東西,顧客在貨架上(緩沖區(qū))買(mǎi)東西。?
生產(chǎn)者消費(fèi)者問(wèn)題,其實(shí)是一個(gè)多線(xiàn)程同步問(wèn)題的經(jīng)典案例。該問(wèn)題描述了兩個(gè)共享固定大小緩沖區(qū)的線(xiàn)程—即所謂的“生產(chǎn)者”和“消費(fèi)者”–在實(shí)際運(yùn)行時(shí)會(huì)發(fā)生的問(wèn)題。生產(chǎn)者的主要作用是生成一定量的數(shù)據(jù)放在緩沖區(qū)中,消費(fèi)者在緩沖區(qū)消耗這些數(shù)據(jù)。但是,要保證生產(chǎn)者不會(huì)在緩沖區(qū)滿(mǎn)時(shí)還往緩沖區(qū)寫(xiě)數(shù)據(jù),消費(fèi)者也不會(huì)在緩沖區(qū)為空時(shí)讀數(shù)據(jù)。?
三種關(guān)系
- 生產(chǎn)者與消費(fèi)者之間是供求關(guān)系(互斥和同步)
- 生產(chǎn)者與生產(chǎn)者之間是競(jìng)爭(zhēng)關(guān)系(互斥)
- 消費(fèi)者與消費(fèi)者之間是競(jìng)爭(zhēng)關(guān)系(互斥)
我們簡(jiǎn)單解釋一下三種關(guān)系。假如我們現(xiàn)在在一家超市,我們們想要買(mǎi)一箱牛奶。牛奶生產(chǎn)商(生產(chǎn)者)生產(chǎn)了牛奶,經(jīng)超市工作人員把牛奶擺放在了貨架上,在這個(gè)過(guò)程過(guò)我們(消費(fèi)者)不能買(mǎi)牛奶,要等待工作人員擺好貨物,所以此時(shí)生產(chǎn)者與消費(fèi)者是互斥關(guān)系。工作人員擺好貨物后,我們(消費(fèi)者)去購(gòu)買(mǎi),此時(shí)生產(chǎn)者與消費(fèi)者是同步關(guān)系。?
一個(gè)貨架上只能擺一個(gè)品牌的貨物,怒能擺其他的,此時(shí)生產(chǎn)者與生產(chǎn)者之間是互斥關(guān)系。?
兩個(gè)或多個(gè)顧客不能同時(shí)買(mǎi)一個(gè)貨物,此時(shí)消費(fèi)者與消費(fèi)者之間是互斥關(guān)系。
我們可以用兩種方法實(shí)現(xiàn)生產(chǎn)者與消費(fèi)者模型。
基于單鏈表的生產(chǎn)者消費(fèi)者模型
我們用兩個(gè)線(xiàn)程分別表示生產(chǎn)者與消費(fèi)者,用單鏈表表示緩沖區(qū)。?
生產(chǎn)者生產(chǎn)數(shù)據(jù),插入到單鏈表的頭部。?
消費(fèi)者消費(fèi)數(shù)據(jù),從單鏈表的頭部讀數(shù)據(jù)。
條件變量
條件變量是利用線(xiàn)程間共享的全局變量進(jìn)行同步的一種機(jī)制,只要包括兩個(gè)動(dòng)作:一個(gè)線(xiàn)程等待”條件變量的條件成立”而掛起;另一個(gè)線(xiàn)程使”條件成立(給出條件成立信號(hào))。?
為了放置競(jìng)爭(zhēng),條件變量的使用總和一個(gè)互斥鎖結(jié)合在一起。
條件變量的類(lèi)型為 pthread_cond_t.?
條件變量的初始化:
1.直接定義一個(gè)全局的條件變量,并利用宏P(guān)THREAD_COND_INITIALIZER進(jìn)行值得初始化。
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;- 1
2.調(diào)用函數(shù)pthread_cond_init
#include<pthread.h> pthread_cond_init (pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);- 1
- 2
- 3
第一個(gè)參數(shù)即為我們動(dòng)態(tài)分配的條件變量cond,除非創(chuàng)建一個(gè)非默認(rèn)屬性的條件變量,否則第二個(gè)參數(shù)attr始終為NULL;?
注意:若不想講條件變量定義成全局的,必須以動(dòng)態(tài)分配的方式創(chuàng)建。
- 1
- 2
- 3
注意:使用此種方式,先destroy條件變量,再free這塊空間。
3.銷(xiāo)毀條件變量
int pthread_cond_destroy(pthread_cond_t* cond);- 1
參數(shù)cond指針即指向我們創(chuàng)建的條件變量。?
4.等待?
我們使用pthread_cond_wait或pthread_cond_timewait函數(shù)等待條件變量變?yōu)檎妗?/p>
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
- 1
- 2
pthread _cond_wait,其第一個(gè)參數(shù)是指向條件變量的指針,第二個(gè)參數(shù)是一個(gè)指向互斥鎖的指針。在上面提到過(guò),條件變量總是和一把互斥鎖協(xié)同使用的。目的是為了防止資源的競(jìng)爭(zhēng)。?
生產(chǎn)者與消費(fèi)者之間是同步互斥關(guān)系的,他們不能同時(shí)訪(fǎng)問(wèn)緩沖區(qū),所以我們需要一把鎖來(lái)約束他們。?
假如我們此時(shí)有兩個(gè)消費(fèi)者A,B在等待資源,生產(chǎn)者申請(qǐng)到了”鎖“,并且生產(chǎn)了一個(gè)產(chǎn)品,釋放鎖。并發(fā)送信號(hào)告訴消費(fèi)者你們可以來(lái)消費(fèi)了。?
假如消費(fèi)者A 率先搶到鎖,買(mǎi)走了產(chǎn)品。B再申請(qǐng)到鎖時(shí),發(fā)現(xiàn)已經(jīng)沒(méi)有產(chǎn)品了,只能等待條件變量為真時(shí),買(mǎi)產(chǎn)品。此時(shí)鎖在B身上,如果B一直在等待,一直不釋放鎖時(shí),會(huì)造成生產(chǎn)者申請(qǐng)不到鎖而造成“死鎖”。所以wait的第二個(gè)參數(shù)就是當(dāng)消費(fèi)者在申請(qǐng)到鎖時(shí),條件變量為假時(shí),及時(shí)的釋放鎖資源。?
wait函數(shù)是無(wú)條件等待。在條件變量為假時(shí),會(huì)一直等下去。timedwait是有條件等待,它多定義了一個(gè)超時(shí),超時(shí)值定義了我們?cè)敢獾却嚅L(zhǎng)時(shí)間。它通過(guò)timespec決定。
5.發(fā)送信號(hào)
int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond);- 1
- 2
當(dāng)生產(chǎn)者生產(chǎn)完畢后需要通知消費(fèi)者。發(fā)送信號(hào)有兩種方式。signal是根據(jù)某種優(yōu)先級(jí)喚醒一個(gè)等待者。broadcast是在資源充足的情況下進(jìn)行廣播,喚醒所有等待者。
代碼實(shí)現(xiàn):
#include<stdio.h> #include<stdlib.h> #include<pthread.h>typedef struct _list {struct _list *next;int _val; }product_list;product_list *head = NULL; static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t need_product = PTHREAD_COND_INITIALIZER;void Init_list(product_list* list) {if(list != NULL){list -> next = NULL;list -> _val = 0;} }void* Consumer(void* _val) {product_list *p = NULL;for(;;){pthread_mutex_lock(&lock);while(head == NULL){pthread_cond_wait(&need_product,&lock);}p = head;head = head -> next;p -> next = NULL;pthread_mutex_unlock(&lock);printf("Consum success,val is:%d\n",p -> _val);free(p);}return NULL; }void* Product(void* _val) {for(;;){sleep(rand() % 2);product_list* p =malloc(sizeof(product_list));pthread_mutex_lock(&lock);Init_list(p);p -> _val = rand() % 1000;p -> next = head;head = p;pthread_mutex_unlock(&lock);printf("Call consumer! Product has producted,val is:%d\n",p->_val);pthread_cond_signal(&need_product);} }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; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
基于環(huán)形隊(duì)列的生產(chǎn)者消費(fèi)者模型
除了基于單鏈表的生產(chǎn)者與消費(fèi)者模型,我們還可以利用信號(hào)量實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模型。
原理
生產(chǎn)者在空格子上生產(chǎn)數(shù)據(jù)。?
消費(fèi)者在有商品的格子上消費(fèi)數(shù)據(jù)。?
注意:
- 生產(chǎn)者先進(jìn)行生產(chǎn)。
- 當(dāng)消費(fèi)者沒(méi)有數(shù)據(jù)要消費(fèi)時(shí),需等待生產(chǎn)者生產(chǎn)。
- 當(dāng)生產(chǎn)者把緩沖區(qū)充滿(mǎn)時(shí),需等待消費(fèi)者消費(fèi),出現(xiàn)空格子時(shí)在生產(chǎn)。?
操作函數(shù)
#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value); int sem_destroy(sem_t *sem); int sem_wait(sem_t *sem); int sem_trywait(sem_t *sem); int sem_post(sem_t *sem);- 1
- 2
- 3
- 4
- 5
- 6
- 7
初始化信號(hào)量sem_init,參數(shù)value為信號(hào)量的值,參數(shù)pshared一般設(shè)為0,表示信號(hào)量用于同一進(jìn)程內(nèi)線(xiàn)程間同步。摧毀信號(hào)量sem_destroy。P操作(申請(qǐng)資源)sem_wait,使信號(hào)量的值-1。V操作(釋放資源)sem_post,使信號(hào)量的值+1。sem_trywait是嘗試申請(qǐng)資源。
代碼實(shí)現(xiàn)
#include<stdio.h> #include<stdlib.h> #include<pthread.h> #include<semaphore.h>#define _SIZE_ 5 sem_t blanks; //表示格子的信號(hào)量 sem_t datas; //表示商品的信號(hào)量 int buf[_SIZE_] ={ 0 };//生產(chǎn)者 void* product(void* arg) {int i = 0;while(1){usleep(500000);sem_wait(&blanks); //生產(chǎn)者申請(qǐng)格子資源int data = rand()%1000;buf[i] = data;printf("Product is:%d\n",data);sem_post(&datas); //每生產(chǎn)一個(gè)商品就需要對(duì)商品信號(hào)量+1++i;i %= _SIZE_;} }//消費(fèi)者 void* consumer(void* arg) {int i = 0;while(1){usleep(500000); sem_wait(&datas); //消費(fèi)者申請(qǐng)商品資源printf("Consumer is%d\n",buf[i]);sem_post(&blanks); //買(mǎi)走一個(gè)商品,就多了一個(gè)空格子++i;i %= _SIZE_;} }int main() {sem_init(&blanks,0,_SIZE_);sem_init(&datas,0,0);pthread_t _consumer;pthread_t _product;pthread_create(&_consumer,NULL,consumer,NULL);pthread_create(&_product,NULL,product,NULL);pthread_join(_consumer,NULL);pthread_join(_product,NULL);sem_destroy(&blanks);sem_destroy(&datas);return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
總結(jié)
以上是生活随笔為你收集整理的Linux--生产者与消费者的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 精子畸形率高能不能做试管婴儿
- 下一篇: 新九品芝麻官剧情介绍