生產者-消費者問題是一個著名的進程同步問題。它描述的爲:有一羣生產者進程在生產產品,並將這些產品提供給消費者進程消費。爲使生產者進程與消費者進程能併發執行,在兩者之間設置一個具有n個緩存區的緩衝池,生產者進程將其所生產的產品放入一個緩衝區;消費者進程可從一個緩衝區中取走產品去消費。儘管所有生產者和消費者進程都是異步方式運行的,但它們之間必須保持同步,既不允許消費者進程到一個空緩衝區取產品,也不允許生產者進程向一個已裝滿產品且尚未被取走的緩衝區中投放產品。
<1> 單生產者和單消費者
#include <stdio.h> #include <pthread.h> #include <semaphore.h> sem_t space_sem,data_sem;//信號量 int buf[10];//緩衝區 void* sem_producter(void* arg) //生產者 { int start = 0; while(1) { sem_wait(&space_sem); //P操作 申請空間,若空間爲0,掛起 int data = rand()%1234; printf("producter data : %d\n",data); buf[start] = data; start++; start %= 10; sem_post(&data_sem);//V操作 申請數據,若數據爲0,掛起 sleep(1); } } void* sem_consumer(void* arg) //消費者 { int start = 0; while(1) { sem_wait(&data_sem); int data = buf[start]; printf("consumer data : %d\n",data); start++; start %= 10; sem_post(&space_sem); //sleep(1); } } int main() { sem_init(&space_sem,0,10);//初始化信號量 sem_init(&data_sem,0,0); pthread_t id1,id2,id3,id4; pthread_create(&id1,NULL,sem_producter,NULL); //創建線程 pthread_create(&id2,NULL,sem_consumer,NULL); pthread_join(id1,NULL);//等待進程 pthread_join(id2,NULL); sem_destroy(&space_sem);//釋放資源 sem_destroy(&data_sem); return 0; }
若生產者sleep(1),生產一個消費一個。當緩衝區爲空時,消費者掛起,直到生產者生產產品纔會喚醒消費者去消費。
若消費者sleep(1),則生產者會先將緩衝區生產滿,然後掛起,直到消費者消費一個,才能喚醒生產者生產產品。
<2> 多生產者多消費者(以兩個生產者兩個消費者爲例)
#include <stdio.h> #include <pthread.h> #include <semaphore.h> sem_t space_sem,data_sem; //信號量 int buf[10];//緩衝區 static start = 0; static begin = 0; void* sem_producter(void* arg) { while(1) { sem_wait(&space_sem); //申請空間 P操作 int data = rand()%1234; printf("producter data : %d\n",data); buf[start] = data; start++; start %= 10; sem_post(&data_sem); //釋放數據 V操作 sleep(1); } } void* sem_consumer(void* arg) { while(1) { sem_wait(&data_sem); //申請數據 P操作 int data = buf[begin]; printf("consumer data : %d\n",data); begin++; begin %= 10; sem_post(&space_sem); //釋放空間 V操作 // sleep(1); } } int main() { sem_init(&space_sem,0,10); //初始化,可用空間爲10 sem_init(&data_sem,0,0); pthread_t id1,id2,id3,id4; pthread_create(&id1,NULL,sem_producter,NULL); pthread_create(&id2,NULL,sem_consumer,NULL); pthread_create(&id3,NULL,sem_producter,NULL); pthread_create(&id4,NULL,sem_consumer,NULL); pthread_join(id1,NULL); pthread_join(id2,NULL); pthread_join(id3,NULL); pthread_join(id4,NULL); sem_destroy(&space_sem); sem_destroy(&data_sem); return 0; }
測試結果: