线程实现生产者消费者实验

来源:互联网 发布:md5判断密码正确java 编辑:程序博客网 时间:2024/05/02 03:55

生产者消费者问题描述如下:

有一个有限缓冲区和两个线程,生产者和消费者,他们分别不停地把产品放到缓冲区和从缓冲区拿走数据,一个生产者在缓冲区满的时候必须等待,而消费者在缓冲区空时也必须等待,又因为缓冲区时临界资源,故要实现两个线程之间的互斥访问。在本实验中采用管道来模拟有限缓冲区,并使用信号量来解决同步和互斥问题。

在这里我们使用三个信号量:mutex,avail,full。其中两个信号量avail和full分别用于解决同步问题,mutex解决互斥的问题。avail表示缓冲区中空单元数,初始值为N,full表示缓冲区中非空单元数,初始值为0,mutex为互斥信号量,初始值为1.

在本实验中,缓冲去为3个单元,每个单元5个字节。另外,使用随机时间延迟的方法实现两个线程的随机访问缓冲区,这更能体现信号量的价值。生产者每次放入一个hello字符串,消费者每次取走一个hello字符串。并且生产者的平均速度是消费者的2倍。源代码:

/*producer_customer.c*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <pthread.h>#include <errno.h>#include <semaphore.h>#include <sys/ipc.h>/*定义有名管道的文件名*/#define MYFIFO"/tmp/myfifo"/*缓冲区单元数*/#define BUFFER_UNITS3/*每个缓冲区单元大小*/#define UNIT_SIZE5/*程序运行时间*/#define RUN_TIME30/*线程最大延时*/#define DELAY_TIME_LEVELS5.0/*管道文件描述符*/int fd;/*程序结束时间点*/time_t end_time;/*三个信号量*/sem_t mutex,full,avail;/*生产者线程*/void *producer(void *arg){int real_write;int delay_time = 0;/*当结束时间点没有到来之前,一直循环*/while( time(NULL) < end_time ){/*生产者的延迟时间*/delay_time = (int)(rand()*DELAY_TIME_LEVELS/(RAND_MAX)/2.0) + 1;sleep(delay_time);/*P操作信号量avail,mutex*/sem_wait(&avail);sem_wait(&mutex);printf("\nProducer:delay = %d\n",delay_time);/*向管道中写数据*/if( (real_write=write(fd,"hello",UNIT_SIZE)) == -1 ){if( errno == EAGAIN )printf("The FIFO has not been read yet,please try later!\n");}elseprintf("Write %d to FIFO\n",real_write);/*V操作信号量full,mutex*/sem_post(&full);sem_post(&mutex);}pthread_exit(NULL);}/*消费者线程*/void *customer(void *arg){unsigned char read_buffer[UNIT_SIZE];int real_read;int delay_time;while( time(NULL) < end_time ){delay_time = (int)(rand()*DELAY_TIME_LEVELS/(RAND_MAX)) + 1;sleep(delay_time);sem_wait(&full);sem_wait(&mutex);memset(read_buffer,0,UNIT_SIZE);printf("\nCustomer: delay = %d\n",delay_time);if( (real_read=read(fd,read_buffer,UNIT_SIZE)) == -1 ){if( errno == EAGAIN )printf("No data yet!\n");}elseprintf("Read %s from FIFO\n",read_buffer);sem_post(&avail);sem_post(&mutex);}pthread_exit(NULL);}int main(void){pthread_t thrd_prd_id,thrd_cst_id;int ret;srand(time(NULL));/*定义程序结束时间点*/end_time = time(NULL) + RUN_TIME;/*创建有名管道*/if( (mkfifo(MYFIFO,O_CREAT | O_EXCL) < 0) && (errno != EEXIST) ){printf("Cannot create fifo!\n");return errno;}/*打开有名管道*/fd = open(MYFIFO,O_RDWR);if( fd == -1 ){printf("Open fifo error!\n");return fd;}/*初始化信号量mutex,avail,full*/ret = sem_init(&mutex,0,1);ret += sem_init(&avail,0,BUFFER_UNITS);ret += sem_init(&full,0,0);if( ret != 0){printf("Any semaphore initialization failed!\n");return ret;}/*创建生产者线程*/ret = pthread_create(&thrd_prd_id,NULL,producer,NULL);if( ret != 0 ){printf("create producer thread error!\n");return ret;}/*创建消费者线程*/ret = pthread_create(&thrd_cst_id,NULL,customer,NULL);if( ret != 0 ){printf("create customer thread error!\n");return ret;}/*分别等待生产者和消费者线程结束*/pthread_join(thrd_prd_id,NULL);pthread_join(thrd_cst_id,NULL);/*关闭管道文件描述符*/close(fd);/*关闭管道文件链接,删除管道文件*/unlink(MYFIFO);return 0;}

编译运行,可以看到运行结果。





原创粉丝点击