多线程编程之:实验内容——“生产者消费者”实验
发布时间:2015-11-12 11:14
发布者:designapp
9.3 实验内容——“生产者消费者”实验 1.实验目的 “生产者消费者”问题是一个著名的同时性编程问题的集合。通过学习经典的“生产者消费者”问题的实验,读者可以进一步熟悉Linux中的多线程编程,并且掌握用信号量处理线程间的同步和互斥问题。 2.实验内容 “生产者—消费者”问题描述如下。 有一个有限缓冲区和两个线程:生产者和消费者。他们分别不停地把产品放入缓冲区和从缓冲区中拿走产品。一个生产者在缓冲区满的时候必须等待,一个消费者在缓冲区空的时候也必须等待。另外,因为缓冲区是临界资源,所以生产者和消费者之间必须互斥执行。它们之间的关系如图9.4所示。 图9.4 生产者消费者问题描述 这里要求使用有名管道来模拟有限缓冲区,并且使用信号量来解决“生产者—消费者”问题中的同步和互斥问题。 3.实验步骤 (1)信号量的考虑。 这里使用3个信号量,其中两个信号量avail和full分别用于解决生产者和消费者线程之间的同步问题,mutex是用于这两个线程之间的互斥问题。其中avail表示有界缓冲区中的空单元数,初始值为N;full表示有界缓冲区中非空单元数,初始值为0;mutex是互斥信号量,初始值为1。 (2)画出流程图。 本实验流程图如图9.5所示。 图9.5 “生产者—消费者”实验流程图 (3)编写代码 本实验的代码中采用的有界缓冲区拥有3个单元,每个单元为5个字节。为了尽量体现每个信号量的意义,在程序中生产过程和消费过程是随机(采取0~5s的随机时间间隔)进行的,而且生产者的速度比消费者的速度平均快两倍左右(这种关系可以相反)。生产者一次生产一个单元的产品(放入“hello”字符串),消费者一次消费一个单元的产品。 /*producer-customer.c*/ #include #include #include #include #include #include #include #include #define MYFIFO "myfifo" /* 缓冲区有名管道的名字 */ #define BUFFER_SIZE 3 /* 缓冲区的单元数 */ #define UNIT_SIZE 5 /* 每个单元的大小 */ #define RUN_TIME 30 /* 运行时间 */ #define DELAY_TIME_LEVELS 5.0 /* 周期的最大值 */ int fd; time_t end_time; sem_t mutex, full, avail; /* 3个信号量 */ /*生产者线程*/ 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"); } } else { printf("Write %d to the 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); /*P操作信号量full和mutex*/ 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"); } } printf("Read %s from FIFO\n", read_buffer); /*V操作信号量avail和mutex*/ sem_post(&avail); sem_post(&mutex); } pthread_exit(NULL); } int main() { pthread_t thrd_prd_id,thrd_cst_id; pthread_t mon_th_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; } /*初始化互斥信号量为1*/ ret = sem_init(&mutex, 0, 1); /*初始化avail信号量为N*/ ret += sem_init(&avail, 0, BUFFER_SIZE); /*初始化full信号量为0*/ 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; } 4.实验结果 运行该程序,得到如下结果: $ ./producer_customer …… Producer: delay = 3 Write 5 to the FIFO Customer: delay = 3 Read hello from FIFO Producer: delay = 1 Write 5 to the FIFO Producer: delay = 2 Write 5 to the FIFO Customer: delay = 4 Read hello from FIFO Customer: delay = 1 Read hello from FIFO Producer: delay = 2 Write 5 to the FIFO …… |
网友评论