1. 程式人生 > 其它 >用訊號量實現消費者-生產者模型

用訊號量實現消費者-生產者模型

技術標籤:Linux程式設計

文章目錄


前言

訊號量:可以實現執行緒(或程序)之間同步,避免資料混亂。提高執行緒併發性。

一、訊號量是什麼?

進化版的互斥鎖(1 --> N)
由於互斥鎖的粒度比較大,如果我們希望在多個執行緒間對某一物件的部分資料進行共享,使用互斥鎖是沒有辦法實現的,只能將整個資料物件鎖住。這樣雖然達到了多執行緒操作共享資料時保證資料正確性的目的,卻無形中導致執行緒的併發性下降。執行緒從並行執行,變成了序列執行。與直接使用單程序無異。
訊號量,是相對摺中的一種處理方式,既能保證同步,資料不混亂,又能提高執行緒併發。

二、使用步驟

1.引入標頭檔案

#include<semaphore.h>

主要函式

1.sem_init函式
初始化一個訊號量
int sem_init(sem_t *sem, int pshared, unsigned int value);
參1:sem訊號量	
參2:pshared取0用於執行緒間;取非0(一般為1)用於程序間	
參3:value指定訊號量初值(決定了佔用訊號量的執行緒的個數)

2.sem_destroy函式
銷燬一個訊號量
int sem_destroy(sem_t *sem);

3.sem_wait函式  
給訊號量加鎖 -- 
int sem_wait(sem_t *sem);

4.sem_trywait函式	
5.sem_timedwait函式	

6.sem_post函式
給訊號量解鎖 ++
 int sem_post(sem_t *sem);	

以上6 個函式的返回值都是:成功返回0, 失敗返回-1,同時設定errno。(注意,它們沒有pthread字首)
sem_t型別,本質仍是結構體。但應用期間可簡單看作為整數,忽略實現細節(類似於使用檔案描述符)。
sem_t sem; 規定訊號量sem不能 < 0。

2.執行緒主函式

T生產者主函式 {
sem_wait(S空);
生產…
sem_post(S滿);
}
/
/
/
T消費者主函式 {
sem_wait(S滿);
消費…
sem_post(S空);
}

3.引用消費者-生產者模型程式碼

/*訊號量實現 生產者 消費者問題*/

#include <stdlib.h>
#include <unistd.h> #include <pthread.h> #include <stdio.h> #include <semaphore.h> #define NUM 5 int queue[NUM]; //全域性陣列實現環形佇列 sem_t blank_number, product_number; //空格子訊號量, 產品訊號量 /*生產者:生產產品(產品++),空格子減少(空格子--)*/ void *producer(void *arg) { int i = 0; while (1) { sem_wait(&blank_number); //(生產者將空格子數--,為0則阻塞等待) queue[i] = rand() % 1000 + 1; //生產一個產品 printf("----Produce---%d\n", queue[i]); sem_post(&product_number); //將產品數++ i = (i+1) % NUM; //藉助下標實現環形 sleep(rand()%3); } } /*消費者:空格子增加(空格子++),產品減少(產品--)*/ void *consumer(void *arg) { int i = 0; while (1) { sem_wait(&product_number); //消費者將產品數--,為0則阻塞等待 printf("-Consume---%d\n", queue[i]); queue[i] = 0; //消費一個產品 sem_post(&blank_number); //消費掉以後,將空格子數++ i = (i+1) % NUM; sleep(rand()%3); } } int main(int argc, char *argv[]) { pthread_t pid, cid; sem_init(&blank_number, 0, NUM); //初始化空格子訊號量為5 sem_init(&product_number, 0, 0); //產品數為0 pthread_create(&pid, NULL, producer, NULL); pthread_create(&cid, NULL, consumer, NULL); pthread_join(pid, NULL); pthread_join(cid, NULL); sem_destroy(&blank_number); sem_destroy(&product_number); return 0; }

總結

訊號量的初值,決定了佔用訊號量的執行緒的個數。