Linux多线程生产者与消费者

Linux多线程是Linux型程序设计中十分重要概念,其中线程同步就更加重要了,生产者与消费者模型就是线程同步的经典例子,下面我将给你三种多线程实现生产者和消费者的例子。

一、生产者与消费者逻辑




关键的问题,在于生产者和消费者什么时候睡眠,又什么时候被唤醒,这就是生产者和消费者模型的关键。

缓冲区模型:


使用唤醒缓冲区,方向为逆时针。

read表示已经读取的位置

write表示即将写入的位置

缓冲区初始状态:

read不等于write。

生产者写满

write==read,即将写的地方为刚读取的位置,就是下一个位置还没有读,所以代表写满。

消费者读完:

read+1=write,即将读的地方为即将写入得位置,还没有写,就不能再读了,这里就代表读完。

二、信号量模型

#include <pthread.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <semaphore.h> 
  
//临界资源描述信息
struct Data
{
	int d[5]  ;      //环形缓冲区
	int  ptr_read;   //已经读位置
	int  ptr_write;  //即将写位置
	sem_t can_read;  //可读数据数目
	sem_t can_write; //可写数据数目
};
  
struct Data data;
int length=5;
static int value=0;//作为环形缓冲区的数据
void init_data(void)
{
	data.ptr_read=4;
	data.ptr_write=0;
	sem_init(&data.can_read,0,0);
	sem_init(&data.can_write,0,length);
	
}
void *thread_consumer(void *arg);
void *thread_producter(void *arg);

  
int main()  
{  
	  init_data();
	 /************创建消费者和生产者线程*******************/
 
    pthread_t consumer,producter;  
    pthread_attr_t attr;
    void *thread_result;  
    /***设置线程为脱离类型***/
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
    /***创建消费者线程***/
    pthread_create(&consumer, &attr, thread_consumer, NULL);  
    /***创建生产者线程***/
    pthread_create(&producter, &attr, thread_producter, NULL);  
    while(1)
    {
    	sleep(2);
    }
}  
  
void *thread_consumer(void *arg)  
{  
	  int count=0;
    while(1)
    {
    	/****随机的消费数据使得问题适应性更广*****/
    	int sleep_time=rand()%3;
    	sleep(sleep_time);
    
    	sem_wait(&data.can_read);//减少可读信号量
    	
    	printf("sub data is = %d \n",data.d[(data.ptr_read+1)%length]);//读出数据
    	data.ptr_read=(data.ptr_read+1)%length;//更新已读位置
    	
      sem_post(&data.can_write);//增加可写信号量
    }
}  

void *thread_producter(void *arg)  
{  
	  int count=0;
    while(1)
    {
    	int sleep_time=rand()%3;
    	sleep(sleep_time);
  
    	int ret=sem_wait(&data.can_write);//减少可写信号量
    	
    	data.d[data.ptr_write]=++value;   //写入新的值
    	printf("------add data is = %d \n",data.d[data.ptr_write]);//打印新生产的值
    	data.ptr_write=(data.ptr_write+1)%length;//更新即将写入的位置
    	
      ret=sem_post(&data.can_read);//增加可读信号量
    }
}
三、条件变量模型

#include <pthread.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <semaphore.h> 
  
//临界资源描述信息
struct Data
{
	int d[5]  ;     //临界资源
	int  ptr_read;   //已经读指针位置
	int  ptr_write;  //即将写指针位置
	pthread_mutex_t mutex1;
	pthread_mutex_t mutex2;
	pthread_cond_t  can_read;
	pthread_cond_t  can_write;
};
  
static int value=0;
struct Data data;
int length=5;
void init_data(void)
{
	data.ptr_read=4;
	data.ptr_write=0;
	pthread_cond_init(&data.can_read,NULL);
	pthread_mutex_init(&data.mutex1,NULL);
	pthread_cond_init(&data.can_write,NULL);
  pthread_mutex_init(&data.mutex2,NULL);
}
void *thread_consumer(void *arg);
void *thread_producter(void *arg);

  
int main()  
{  
	  init_data();
	 /************创建消费者和生产者线程*******************/  
    pthread_t consumer,producter;  
    pthread_attr_t attr;
    void *thread_result;  
    /***设置线程为脱离类型***/
    pthread_attr_init(&attr); 
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
    /***创建消费者线程***/
    pthread_create(&consumer, &attr, thread_consumer, NULL);   
    /***创建生产者线程***/
    pthread_create(&producter, &attr, thread_producter, NULL);  
    while(1)
    {
    	sleep(2);
    }
}  
  
void *thread_consumer(void *arg)  
{  
	  sleep(3);//消费者先睡眠2s,让生产者生产数据
    while(1)
    {
    	/****随机的消费数据使得问题适应性更广*****/
    	int sleep_time=rand()%3;
    	sleep(sleep_time);
    
    pthread_mutex_lock(&data.mutex1);
    
    if((data.ptr_read+1)%length==data.ptr_write)  //即将读的位置还没有写好数据
    	   pthread_cond_wait(&data.can_read,&data.mutex1);
    printf("sub data:%d\n",data.d[(data.ptr_read+1)%length]);//唤醒后即可读取数据
    data.ptr_read=(data.ptr_read+1)%length;                      //更新已经读取指针位置
    
    pthread_cond_signal(&data.can_write); 
                               
    pthread_mutex_unlock(&data.mutex1);
    }
}  

void *thread_producter(void *arg)  
{  
	  int count=0; 
	  
    while(1)
    {
    	int sleep_time=rand()%3;
    	sleep(sleep_time);
  
    pthread_mutex_lock(&data.mutex2);
    if(data.ptr_write==data.ptr_read)   //生产者即将写的位置为消费者即将读的位置
				pthread_cond_wait(&data.can_write,&data.mutex2);//等待消费者
    data.d[data.ptr_write]=++value;//写入数据
    printf("------add data:%d \n",data.d[data.ptr_write]);
    data.ptr_write=(data.ptr_write+1)%length;//写指针后移
    
    pthread_cond_signal(&data.can_read);//通知消费者
    pthread_mutex_unlock(&data.mutex2);
    }
}
四、线程消息模型

#include <stdio.h>
#include <pthread.h>
#include <signal.h>

struct Data
{
	int d[5];
	int ptr_write;//将要写入数据的位置
	int ptr_read;//已经读取过数据的位置
	int can_write;
	int can_read;
};

 pthread_t thread1,thread2;
struct Data data;
int value=0;
int length=5;
void *producer(void *pvoid)
{ 
	int signum;
	sigset_t sig;
	sigemptyset(&sig);
	sigaddset(&sig,SIGUSR1);
	pthread_sigmask(SIG_BLOCK,&sig,NULL);//设置该线程的信号屏蔽字为SIGUSR1
	
	data.d[data.ptr_write]=++value;
	printf("produce new data : %d\n",data.d[data.ptr_write]);
  data.ptr_write=(data.ptr_write+1)%length;
  
	while(1)
	{
		sleep(rand()%3); //随机睡眠
		if(data.ptr_write==data.ptr_read)
			{
				 data.can_write=0;
		     sigwait(&sig,&signum);//睡眠等待SIGUSR1信号的到来
		   }
		data.d[data.ptr_write]=++value;
		printf("produce new data : %d\n",data.d[data.ptr_write]);
    data.ptr_write=(data.ptr_write+1)%length;
    if(data.can_read==0)
    	{
    		data.can_read=1;
    		pthread_kill(thread2,SIGUSR2);
    	}
	}
}

void *consumer(void *pvoid)
{ 	
	sleep(1);
	int signum;
	sigset_t sig;
	sigemptyset(&sig);
	sigaddset(&sig,SIGUSR2);
	pthread_sigmask(SIG_BLOCK,&sig,NULL);//设置该线程的信号屏蔽字为SIGUSR2
	while(1)
	{
		sleep(rand()%3); //随机睡眠
		if((data.ptr_read+1)%length==data.ptr_write)
			{ 
				 data.can_read=0;
		     sigwait(&sig,&signum);//睡眠等待SIGUSR1信号的到来 
		  }
		printf("------consumer new data : %d\n",data.d[(data.ptr_read+1)%length]);
    data.ptr_read=(data.ptr_read+1)%length;
		if(data.can_write==0)
			{
				data.can_write=1;
				pthread_kill(thread1,SIGUSR1);
			}
	}
}

void main()
{
	      data.ptr_read=4;
	      data.ptr_write=0;
	      data.can_read=0;
	      data.can_write=1;
	      
	     struct sigaction act;
       act.sa_handler=SIG_IGN;
       sigemptyset(&act.sa_mask);
       act.sa_flags=0;
       sigaction(SIGUSR1,&act,0);//设置信号SIGUSR1的处理方式忽略
       sigaction(SIGUSR2,&act,0);//设置信号SIGUSR1的处理方式忽略
	     
	      pthread_create(&thread1,NULL,producer,NULL);
        pthread_create(&thread2,NULL,consumer,NULL);
  
        pthread_detach(thread1);
        pthread_detach(thread2);
  
  while(1)
  {
  	sleep(2);
  }
}
编译命令gcc -D_REENTRANT -lpthread test4.c -o test4


  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值