用訊號量實現消費者-生產者模型
阿新 • • 發佈:2021-01-28
技術標籤: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;
}
總結
訊號量的初值,決定了佔用訊號量的執行緒的個數。