Linux下多執行緒模擬生產者/消費者問題
阿新 • • 發佈:2019-01-06
/*用執行緒的同步和互斥來實現"生產者-消費者"問題.*/ /* 多生產者多消費者多緩衝區 生產者和消費者不可同時進行 */ #include <stdio.h> #include <stdlib.h> //#include <unistd.h> #include <pthread.h> #include <semaphore.h> #include <time.h> #define M 10 // 緩衝數目 int in = 0; // 生產者放置產品的位置 int out = 0; // 消費者取產品的位置 int buff[M] = {0}; // 緩衝初始化為0,開始時沒有產品 int buffer=0; //單緩衝 sem_t empty_sem; // 同步訊號量, 當滿了時阻止生產者放產品 sem_t full_sem; // 同步訊號量, 當沒產品時阻止消費者消費 pthread_mutex_t mutex; // 互斥訊號量, 一次只有一個執行緒訪問緩衝 int product_id = 0; //生產者id int consumer_id = 0; //消費者id int product_sum=0; int consumer_sum=0; struct timeval start; //記錄時間 struct timeval end; unsigned long timer; /* 列印緩衝情況 */ void print() { int i; for(i = 0; i < M; i++) printf("%d ", buff[i]); } /* 生產者方法 (多緩衝)*/ void *product(void * arg) { int id = ++product_id; int t=*(int *)arg; //t生產者生產時間 while(1) { // 用sleep的數量可以調節生產和消費的速度,便於觀察 sleep(t); //sleep(1); sem_wait(&empty_sem); pthread_mutex_lock(&mutex); gettimeofday(&end,NULL); //生產開始時間 in = in % M; product_sum++; timer = 1000000 * (end.tv_sec-start.tv_sec)+ end.tv_usec-start.tv_usec; printf("time:%ldus product_%d in %d. buffer: ", timer,id, in+1); //printf("timer = %ld us\n",timer); buff[in] = 1; print(); printf("\t%d\n",product_sum); ++in; pthread_mutex_unlock(&mutex); sem_post(&full_sem); } } /* 生產者方法 (單緩衝)*/ void *product1(void * arg) { int id = ++product_id; int t=*(int *)arg; while(1) { sleep(t); sem_wait(&empty_sem); pthread_mutex_lock(&mutex); gettimeofday(&end,NULL); product_sum++; timer = 1000000 * (end.tv_sec-start.tv_sec)+ end.tv_usec-start.tv_usec; printf("time:%ld product_%d is producing.SUM=%d\n",timer,id,product_sum); buffer=1; pthread_mutex_unlock(&mutex); sem_post(&full_sem); } } /* 生產者方法 交換wait(metux) wait(empty)*/ void *product2(void * arg) { int id = ++product_id; int t=*(int *)arg; while(1) { sleep(t); //sleep(1); pthread_mutex_lock(&mutex); sem_wait(&empty_sem); gettimeofday(&end,NULL); in = in % M; product_sum++; timer = 1000000 * (end.tv_sec-start.tv_sec)+ end.tv_usec-start.tv_usec; printf("time:%ldus product_%d in %d. buffer: ", timer,id, in+1); //printf("timer = %ld us\n",timer); buff[in] = 1; print(); printf("\t%d\n",product_sum); ++in; pthread_mutex_unlock(&mutex); sem_post(&full_sem); } } /* 生產者方法 交換signal(metux) signal(empty)*/ void *product3(void * arg) { int id = ++product_id; int t=*(int *)arg; while(1) { sleep(t); //sleep(1); sem_wait(&empty_sem); pthread_mutex_lock(&mutex); gettimeofday(&end,NULL); in = in % M; product_sum++; timer = 1000000 * (end.tv_sec-start.tv_sec)+ end.tv_usec-start.tv_usec; printf("time:%ldus product_%d in %d. buffer: ", timer,id, in+1); //printf("timer = %ld us\n",timer); buff[in] = 1; print(); printf("\t%d\n",product_sum); ++in; sem_post(&full_sem); pthread_mutex_unlock(&mutex); } } /* 生產者方法 生產者消費者同時訪問緩衝區*/ void *product4(void * arg) { int id = ++product_id; int t=*(int *)arg; while(1) { sleep(t); //sleep(1); sem_wait(&empty_sem); pthread_mutex_lock(&mutex); gettimeofday(&end,NULL); in = in % M; product_sum++; timer = 1000000 * (end.tv_sec-start.tv_sec)+ end.tv_usec-start.tv_usec; printf("time:%ldus product_%d in %d. buffer: ", timer,id, in+1); //printf("timer = %ld us\n",timer); buff[in] = 1; print(); printf("\t%d\n",product_sum); ++in; sem_post(&full_sem); pthread_mutex_unlock(&mutex); } } /* 消費者方法(多緩衝) */ void *consumer(void * arg) { int id = ++consumer_id; int t=*(int *)arg; while(1) { // 用sleep的數量可以調節生產和消費的速度 sleep(t); sem_wait(&full_sem); pthread_mutex_lock(&mutex); gettimeofday(&end,NULL); //消費生產時間 consumer_sum++; out = out % M; timer = 1000000 * (end.tv_sec-start.tv_sec)+ end.tv_usec-start.tv_usec; printf("time:%ldus consumer_%d in %d. buffer: ", timer,id, out+1); buff[out] = 0; print(); printf("\t%d\n",consumer_sum); ++out; pthread_mutex_unlock(&mutex); sem_post(&empty_sem); } } /* 消費者方法(單緩衝) */ void *consumer1(void *arg) { int id = ++consumer_id; int t=*(int *)arg; while(1) { sleep(t); sem_wait(&full_sem); pthread_mutex_lock(&mutex); gettimeofday(&end,NULL); consumer_sum++; timer = 1000000 * (end.tv_sec-start.tv_sec)+ end.tv_usec-start.tv_usec; printf("time:%ld consumer_%d is consumeing.SUM=%d\n",timer,id, consumer_sum); buffer=0; pthread_mutex_unlock(&mutex); sem_post(&empty_sem); } } /* 消費者方法 wait(metux) wait(empty)互換 */ void *consumer2(void * arg) { int id = ++consumer_id; int t=*(int *)arg; while(1) { sleep(t); pthread_mutex_lock(&mutex); sem_wait(&full_sem); gettimeofday(&end,NULL); consumer_sum++; out = out % M; timer = 1000000 * (end.tv_sec-start.tv_sec)+ end.tv_usec-start.tv_usec; printf("time:%ldus consumer_%d in %d. buffer: ", timer,id, out+1); buff[out] = 0; print(); printf("\t%d\n",consumer_sum); ++out; pthread_mutex_unlock(&mutex); sem_post(&empty_sem); } } /* 消費者方法 signal(metux) signal(empty)互換*/ void *consumer3(void * arg) { int id = ++consumer_id; int t=*(int *)arg; while(1) { sleep(t); sem_wait(&full_sem); pthread_mutex_lock(&mutex); gettimeofday(&end,NULL); consumer_sum++; out = out % M; timer = 1000000 * (end.tv_sec-start.tv_sec)+ end.tv_usec-start.tv_usec; printf("time:%ldus consumer_%d in %d. buffer: ", timer,id, out+1); buff[out] = 0; print(); printf("\t%d\n",consumer_sum); ++out; sem_post(&empty_sem); pthread_mutex_unlock(&mutex); } } /*配置生產者消費者引數*/ void config(int *N1,int *N2,int *T1,int *T2) { FILE *fp; if (!(fp=fopen("config.txt","r"))) { printf("Error in open file!\n"); exit(1); } fscanf(fp,"%d %d %d %d",N1,N2,T1,T2); fclose(fp); } /*選擇選單*/ void menu() { printf("------------------------------------------------------------\n"); printf("------1-多生產者多消費者多緩衝\n"); printf("------2-多生產者多消費者單緩衝\n"); printf("------3-單生產者單消費者單緩衝\n"); printf("------4-單生產者單消費者多緩衝\n"); printf("------5-單生產者多消費者多緩衝\n"); printf("------6-單生產者多消費者單緩衝\n"); printf("------7-多生產者單消費者多緩衝\n"); printf("------8-多生產者單消費者單緩衝\n"); printf("------9-生產者 wait(metux) wait(empty)互換\n"); printf("------10-生產者 signal(metux) signal(empty)互換\n"); printf("------11-消費者 wait(metux) wait(empty)互換\n"); printf("------12-消費者 signal(metux) signal(empty)互換\n"); printf("------0-退出\n"); printf("-------------------------------------------------------------\n"); printf("\n"); } /*多緩衝*/ void f1(int N1,int N2,int T1,int T2,void *product,void *consumer) { //N1,N2分別是生產者消費者數目 //T1,T2分別是生產消費時間 pthread_t id1[N1]; pthread_t id2[N2]; int i; int ret1[N1]; int ret2[N2]; // 初始化同步訊號量 int ini1 = sem_init(&empty_sem, 0, M); //訊號量將被程序內的執行緒共享 int ini2 = sem_init(&full_sem, 0, 0); if(ini1 && ini2 != 0) { printf("sem init failed \n"); exit(1); } //初始化互斥訊號量 int ini3 = pthread_mutex_init(&mutex, NULL); if(ini3 != 0) { printf("mutex init failed \n"); exit(1); } // 建立N1個生產者執行緒 for(i = 0; i < N1; i++) { ret1[i] = pthread_create(&id1[i], NULL, product,&T1); if(ret1[i] != 0) { printf("product%d creation failed \n", i); exit(1); } } //建立N2個消費者執行緒 for(i = 0; i < N2; i++) { ret2[i] = pthread_create(&id2[i], NULL, consumer, &T2); if(ret2[i] != 0) { printf("consumer%d creation failed \n", i); exit(1); } } //銷燬執行緒 for(i = 0; i < N1; i++) { pthread_join(id1[i],NULL); } for(i = 0; i < N2; i++) { pthread_join(id2[i],NULL); } exit(0); } /*單緩衝*/ void f2(int N1,int N2,int T1,int T2,void *product,void *consumer) { pthread_t id1[N1]; pthread_t id2[N2]; int i; int ret1[N1]; int ret2[N2]; int ini1 = sem_init(&empty_sem, 0, 1); int ini2 = sem_init(&full_sem, 0, 0); if(ini1 && ini2 != 0) { printf("sem init failed \n"); exit(1); } int ini3 = pthread_mutex_init(&mutex, NULL); if(ini3 != 0) { printf("mutex init failed \n"); exit(1); } for(i = 0; i < N1; i++) { ret1[i] = pthread_create(&id1[i], NULL, product,&T1); if(ret1[i] != 0) { printf("product%d creation failed \n", i); exit(1); } } for(i = 0; i < N2; i++) { ret2[i] = pthread_create(&id2[i], NULL, consumer,&T2); if(ret2[i] != 0) { printf("consumer%d creation failed \n", i); exit(1); } } for(i = 0; i < N1; i++) { pthread_join(id1[i],NULL); } for(i = 0; i < N2; i++) { pthread_join(id2[i],NULL); } exit(0); } int main(int argc,char* argv) { menu(); int c; //選擇功能 scanf("%d",&c); int N1,N2,T1,T2; config(&N1,&N2,&T1,&T2); switch(c) { case 1: gettimeofday(&start,NULL); //程式開始時間 f1(N1,N2,T1,T2,product,consumer); break; case 2: gettimeofday(&start,NULL); f2(N1,N2,T1,T2,product1,consumer1); break; case 3: gettimeofday(&start,NULL); f2(1,1,T1,T2,product1,consumer1); break; case 4: gettimeofday(&start,NULL); f1(1,1,T1,T2,product,consumer); break; case 5: gettimeofday(&start,NULL); f1(1,N2,T1,T2,product,consumer); break; case 6: gettimeofday(&start,NULL); f2(1,N2,T1,T2,product1,consumer1); break; case 7: gettimeofday(&start,NULL); f1(N1,1,T1,T2,product,consumer); break; case 8: gettimeofday(&start,NULL); f2(N1,1,T1,T2,product1,consumer1); break; case 9: gettimeofday(&start,NULL); f1(N1,N2,T1,T2,product2,consumer); break; case 10: gettimeofday(&start,NULL); f1(N1,N2,T1,T2,product3,consumer); break; case 11: gettimeofday(&start,NULL); f1(N1,N2,T1,T2,product,consumer2); break; case 12: gettimeofday(&start,NULL); f1(N1,N2,T1,T2,product,consumer3); break; case 0: break; } return 0; }