1. 程式人生 > >Linux下多執行緒模擬生產者/消費者問題

Linux下多執行緒模擬生產者/消費者問題

/*用執行緒的同步和互斥來實現"生產者-消費者"問題.*/
/*
多生產者多消費者多緩衝區 生產者和消費者不可同時進行
*/
#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;
}