Linux--生產者與消費者

http://blog.csdn.net/gebushuaidanhenhuai/article/details/74011636

基本概念

提到生產者和消費者,我們最有可能想到的是商店賣東西,顧客在貨架上(緩沖區)買東西。?
生產者消費者問題,其實是一個多線程同步問題的經典案例。該問題描述了兩個共享固定大小緩沖區的線程—即所謂的“生產者”和“消費者”–在實際運行時會發生的問題。生產者的主要作用是生成一定量的數據放在緩沖區中,消費者在緩沖區消耗這些數據。但是,要保證生產者不會在緩沖區滿時還往緩沖區寫數據,消費者也不會在緩沖區為空時讀數據。?
生產者與消費者

三種關系


  • 生產者與消費者之間是供求關系(互斥和同步)
  • 生產者與生產者之間是競爭關系(互斥)
  • 消費者與消費者之間是競爭關系(互斥)

我們簡單解釋一下三種關系。假如我們現在在一家超市,我們們想要買一箱牛奶。牛奶生產商(生產者)生產了牛奶,經超市工作人員把牛奶擺放在了貨架上,在這個過程過我們(消費者)不能買牛奶,要等待工作人員擺好貨物,所以此時生產者與消費者是互斥關系。工作人員擺好貨物后,我們(消費者)去購買,此時生產者與消費者是同步關系。?
一個貨架上只能擺一個品牌的貨物,怒能擺其他的,此時生產者與生產者之間是互斥關系。?
兩個或多個顧客不能同時買一個貨物,此時消費者與消費者之間是互斥關系。

我們可以用兩種方法實現生產者與消費者模型。

基于單鏈表的生產者消費者模型

我們用兩個線程分別表示生產者與消費者,用單鏈表表示緩沖區。?
生產者生產數據,插入到單鏈表的頭部。?
消費者消費數據,從單鏈表的頭部讀數據。

條件變量


條件變量是利用線程間共享的全局變量進行同步的一種機制,只要包括兩個動作:一個線程等待”條件變量的條件成立”而掛起;另一個線程使”條件成立(給出條件成立信號)。?
為了放置競爭,條件變量的使用總和一個互斥鎖結合在一起。

條件變量的類型為 pthread_cond_t.?
條件變量的初始化:

1.直接定義一個全局的條件變量,并利用宏PTHREAD_COND_INITIALIZER進行值得初始化。

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  • 1

2.調用函數pthread_cond_init

#include<pthread.h>
pthread_cond_init (pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
  • 1
  • 2
  • 3

第一個參數即為我們動態分配的條件變量cond,除非創建一個非默認屬性的條件變量,否則第二個參數attr始終為NULL;?
注意:若不想講條件變量定義成全局的,必須以動態分配的方式創建。

pthread_cond_t *cond = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
  • 1
  • 2
  • 3

注意:使用此種方式,先destroy條件變量,再free這塊空間。

3.銷毀條件變量

int pthread_cond_destroy(pthread_cond_t* cond);
  • 1

參數cond指針即指向我們創建的條件變量。?
4.等待?
我們使用pthread_cond_wait或pthread_cond_timewait函數等待條件變量變為真。

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,其第一個參數是指向條件變量的指針,第二個參數是一個指向互斥鎖的指針。在上面提到過,條件變量總是和一把互斥鎖協同使用的。目的是為了防止資源的競爭。?
生產者與消費者之間是同步互斥關系的,他們不能同時訪問緩沖區,所以我們需要一把鎖來約束他們。?
假如我們此時有兩個消費者A,B在等待資源,生產者申請到了”鎖“,并且生產了一個產品,釋放鎖。并發送信號告訴消費者你們可以來消費了。?
假如消費者A 率先搶到鎖,買走了產品。B再申請到鎖時,發現已經沒有產品了,只能等待條件變量為真時,買產品。此時鎖在B身上,如果B一直在等待,一直不釋放鎖時,會造成生產者申請不到鎖而造成“死鎖”。所以wait的第二個參數就是當消費者在申請到鎖時,條件變量為假時,及時的釋放鎖資源。?
wait函數是無條件等待。在條件變量為假時,會一直等下去。timedwait是有條件等待,它多定義了一個超時,超時值定義了我們愿意等待多長時間。它通過timespec決定。

5.發送信號

int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
  • 1
  • 2

當生產者生產完畢后需要通知消費者。發送信號有兩種方式。signal是根據某種優先級喚醒一個等待者。broadcast是在資源充足的情況下進行廣播,喚醒所有等待者。

代碼實現:


#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

這里寫圖片描述

基于環形隊列的生產者消費者模型

除了基于單鏈表的生產者與消費者模型,我們還可以利用信號量實現生產者消費者模型。

原理

生產者在空格子上生產數據。?
消費者在有商品的格子上消費數據。?
注意:

  • 生產者先進行生產。
  • 當消費者沒有數據要消費時,需等待生產者生產。
  • 當生產者把緩沖區充滿時,需等待消費者消費,出現空格子時在生產。?
    這里寫圖片描述

操作函數

#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

初始化信號量sem_init,參數value為信號量的值,參數pshared一般設為0,表示信號量用于同一進程內線程間同步。摧毀信號量sem_destroy。P操作(申請資源)sem_wait,使信號量的值-1。V操作(釋放資源)sem_post,使信號量的值+1。sem_trywait是嘗試申請資源。

代碼實現

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>#define _SIZE_ 5
sem_t blanks; //表示格子的信號量
sem_t datas;  //表示商品的信號量
int buf[_SIZE_] ={ 0 };//生產者
void* product(void* arg)
{int i = 0;while(1){usleep(500000);sem_wait(&blanks); //生產者申請格子資源int data = rand()%1000;buf[i] = data;printf("Product is:%d\n",data);sem_post(&datas); //每生產一個商品就需要對商品信號量+1++i;i %= _SIZE_;}
}//消費者
void* consumer(void* arg)
{int i = 0;while(1){usleep(500000);   sem_wait(&datas);  //消費者申請商品資源printf("Consumer is%d\n",buf[i]);sem_post(&blanks); //買走一個商品,就多了一個空格子++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

這里寫圖片描述


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384058.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384058.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384058.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

進程的掛起以及可重入函數

相關接口 ????pause 函數用于將進程掛起. 如果信號的處理動作是終止進程, 則進程終止, pause 函數沒有返回值; 如果信號的處理動作是忽略, 則進程被掛起, pause函數不返回, 如果信號的處理動作是捕捉, 則調用信號處理動作之后pause 返回 -1.來看一段代碼 #include<s…

POJ1236Network of Schools——強連通分量縮點建圖

【題目描述】 A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distri…

C——通過調用函數分配內存

http://blog.csdn.net/u012627502/article/details/3579724 1&#xff09;以返回值方式返回&#xff1a;把動態分配的存儲位置地址&#xff0c;賦值給指針類型返回值&#xff08;不同于被調用函數的自動變量地址&#xff09; 2&#xff09;以形參形式返回&#xff1a;二級指針類…

gdb調試多進程程序

1.gdb下調試多進程程序只需要以下幾條命令即可 ???????? ????除此之外還可以查看正在調試的進程 info inferiors, 同時也可以將當前正在調試的進程切換到另外一個進程中讓其取運行 ????2.代碼調試演示 #include<stdio.h> #include<stdlib.h> #…

BZOJ1123-BLO——強連通分量求割點+計數

【題目描述】 Byteotia城市有n個 towns m條雙向roads. 每條 road 連接 兩個不同的 towns ,沒有重復的road. 所有towns連通。Input 輸入n<100000 m<500000及m條邊Output 輸出n個數&#xff0c;代表如果把第i個點去掉&#xff0c;將有多少對點不能互通。Sample Input 5…

關于memcpy和memmove兩函數的區別

http://blog.csdn.net/caowei840701/article/details/8491836 [cpp] view plaincopy <p> 關于memcpy和memmove兩個c標準庫函數&#xff0c;其功能都是將一塊內存區域中的指定大小內容復制到目標內存中&#xff0c;在翻閱c標準庫實現的源代碼我們發現他們是有區別的。&…

判斷字符串出棧合法性

先來看說一下思路 接下來就是寫代碼了 int StackOrder(SeqStack* stack, char* input, char* output, int size_input, int size_output) {if(stack NULL || input NULL || output NULL){return 0;}int i_input 0;int j_output 0;SeqStackType value;for(; j_output <…

CodeForces - 1200C——小模擬

【題目描述】 Amugae is in a very large round corridor. The corridor consists of two areas. The inner area is equally divided by n sectors, and the outer area is equally divided by m sectors. A wall exists between each pair of sectors of same area (inner o…

1 單例模式

達內 閔大神 //餓漢單例模式 #include <iostream> using namespace std;class Singleton { public:static Singleton& getInstance(){return s_instance;} private:Singleton(){}Singleton(const Singleton& that){}static Singleton s_instance;//靜態成員變量 …

共享棧

1.定義 所謂共享棧就是利用一個數組實現兩個棧. 先來看一下共享棧的數據結構 typedef struct SharedStack {int top1;int top2;SeqStackType* data; }SharedStack; 2. 初始化 void SharedStackInit(SharedStack* stack) {if(stack NULL){return;//非法輸入}stack -> top…

BZOJ1018 | SHOI2008-堵塞的交通traffic——線段樹維護區間連通性+細節

【題目描述】 BZOJ1018 | SHOI2008-堵塞的交通traffic 有一天&#xff0c;由于某種穿越現象作用&#xff0c;你來到了傳說中的小人國。小人國的布局非常奇特&#xff0c;整個國家的交通系統可 以被看成是一個2行C列的矩形網格&#xff0c;網格上的每個點代表一個城市&#xff0…

C++ 函數隱藏

C該函數隱藏 只有基類成員函數的定義已聲明virtualkeyword&#xff0c;當在派生類中的時間&#xff0c;以支付功能實現&#xff0c;virtualkeyword可以從時間被添加以增加。它不影響多狀態。 easy混淆視聽&#xff0c;掩蓋&#xff1a; &#xff0c;規則例如以下&#xff1a; …

迷宮求解(遞歸)

首先來看一下迷宮簡易圖 ???????????????????????????? ????我們用 0 來表示該位置是墻, 用 1 來表示該位置是路. 所以, 我們在處理迷宮問題的時候可以將其看成一個二維數組即可, 而對應的每一條路我們可以用坐標的形式將其表示, 所以還需要…

CodeForces - 786C——二分+模擬?

【題目描述】 Rick and Morty want to find MR. PBH and they cant do it alone. So they need of Mr. Meeseeks. They Have generated n Mr. Meeseeks, standing in a line numbered from 1 to n. Each of them has his own color. i-th Mr. Meeseeks color is ai.Rick and M…

迷宮求解(非遞歸)

上篇文章寫出了利用函數形成棧楨的特性完成迷宮求解問題, 本篇文章我們自己手動維護一個棧, 其進行出棧, 入棧, 取棧頂元素, 來完成迷宮求解尋路的過程 ????思路和以前一樣, 首先, 我們先定義一個棧, 對其初始化, 同時, 定義一個迷宮地圖, 對該地圖進行初始化, 先判斷當前…

數據結構練習——雙向鏈表

http://www.cnblogs.com/-Lei/archive/2012/04/10/2440399.html 復習一下數據結構。。。。說不準下個星期就用上了 只不過寫的很簡單&#xff0c;沒有封裝 DoubleLinkList.h #ifndef GUARD_DoubleLinkList_h #define GUARD_DoubleLinkList_h#include <stdio.h>struct Li…

CodeChef - DGCD——樹鏈剖分+差分

【題目描述】 Youre given a tree on N vertices. Each vertex has a positive integer written on it, number on the ith vertex being vi. Your program must process two types of queries :1. Find query represented by F u v : Find out gcd of all numbers on the uniq…

UVa272-TeX中的引號

【題目描述】 傳送門 【題目分析】 今天開始刷紫書的題目啦 這道題很簡單&#xff0c;需要注意的是cgetchar()需要加上括號&#xff0c;因為賦值語句的優先級比判等低 而且書中說好像最好用整型變量&#xff0c;因為EOF的值為-1&#xff0c;在字符變量中沒有這個值。&#xf…

C++中友元(友元函數和友元類)的用法和功能

http://blog.csdn.net/adriano119/article/details/5914443/ 采用類的機制后實現了數據的隱藏與封裝&#xff0c;類的數據成員一般定義為私有成員&#xff0c;成員函數一般定義為公有的&#xff0c;依此提供類與外界間的通信接口。但是&#xff0c;有時需要定義一些函數&#x…

線程的終止分離

1.線程的終止 注意該函數是針對用戶級別的, 其中 retal 必須指向一個全局變量, 或者是一個 malloc 分配的, 因為如果是線程的局部變量, 當該線程退出時, 其他線程不能得到這個變量, 因為線程的局部變量各自私有 2. 現成的取消 其中thread是線程的 tid 3.線程的等待與分離 (1)…