Linux C:利用兩個執行緒實現生產者消費者模型
阿新 • • 發佈:2019-02-01
在使用執行緒實現消費者生產者模型前,簡單介紹一下執行緒的概念。
執行緒是程序的一個實體,對於程序而言,程序是程式資源分配的最小單元,這在之前提及過;而對於執行緒,它是程式執行的最小單元,即CPU排程和分派的基本單位,它附屬於程序,同樣也能獨立執行。關於資源分配上,執行緒基本不擁有系統資源,只擁有執行中必不可少的一些資源如程式計數器,棧等。
對於執行緒同樣有互斥和同步問題,互斥是多個執行緒之間操作同個共享資料時使某個執行緒操作,而其他的執行緒阻塞,直到資源解鎖才能訪問。同步則是令執行緒間按一定的順序去執行。下面的模型就是採用同步機制使一個執行緒作為生產者,向全域性字元陣列寫入資料,而另一個執行緒作為消費者,從陣列中讀取資料,通過兩個訊號量的P、V操作實現兩執行緒的順序先後,兩者間為“先生產再消費”,即同步來實現。
具體實現程式碼如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <semaphore.h> #define TEXT_SZ 1024 sem_t sem1; sem_t sem2; char text[TEXT_SZ]; void *write(void *text) //生產者資料輸入函式 { while(1) { sem_wait(&sem1); //訊號量sem1 p操作 printf("(producer) write some text:"); if(fgets((char *)text, TEXT_SZ, stdin) == NULL) //寫資料到全域性陣列 { printf("write error!\n"); exit(1); } if(strncmp((char *)text,"end",3) == 0) //輸入end退出執行緒1 { sem_post(&sem2); //訊號量sem2 v操作 break; } sem_post(&sem2); //訊號量sem2 v操作 } } void *read(void *text) //消費者讀取資料函式 { while(1) { sem_wait(&sem2); //訊號量sem2 p操作 printf("(customer) read the text:%s\n",(char *)text); //輸出讀到的資料 if(strncmp((char *)text,"end",3) == 0) //讀取到end,退出執行緒2 { sem_post(&sem1); //訊號量sem1 v操作 break; } sem_post(&sem1); //訊號量sem1 v操作 } } int main() { pthread_t thread1; pthread_t thread2; int ret1; int ret2; if(sem_init(&sem1,0,1) == -1) //初始化訊號量sem1 { printf("init sem1 error!\n"); exit(1); } if(sem_init(&sem2,0,0) == -1) //初始化訊號量sem2 { printf("init sem2 error!\n"); exit(1); } if(memset(text,0,sizeof(text)) == NULL) { printf("memset error!\n"); exit(1); } ret1 = pthread_create(&thread1,NULL,(void *)write,(void *)text);//建立執行緒1 if(ret1 < 0) { printf("thread1 create error!\n"); exit(1); } ret2 = pthread_create(&thread2,NULL,(void *)read,(void *)text);//建立執行緒2 if(ret2 < 0) { printf("thread2 create error!\n"); exit(1); } pthread_join(thread1,NULL); //等待執行緒1退出 pthread_join(thread2,NULL);//等待執行緒2退出 if(sem_destroy(&sem1) == -1) //刪除訊號量sem1 { printf("delete sem1 error!\n"); exit(1); } if(sem_destroy(&sem2) == -1) //刪除訊號量sem2 { printf("delete sem2 error!\n"); exit(1); } return 0; }