该问题如下:
有一个有限缓冲区(在这里使用命名管道实现FIFO式缓冲区)和两个线程:生产者和消费者
一个生产者在缓冲区满的时候必须等待,消费者在缓冲区为空的时候也必须等待
在该程序中定义3个信号量:
avail:表示有界缓冲区中的空单元数,初始值为N
full:表示有界缓冲区中非空单元数,初始值为0
mutex:互斥信号量,初始值为1
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/ipc.h> #include <semaphore.h> #include <errno.h> #include <pthread.h> #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,avail,full; const char *content = "hello"; void *producer(void *arg) { int len; int delay; while(time(NULL)<end_time) { delay = (int)(rand()*DELAY_TIME_LEVELS/(RAND_MAX)/2.0)+1; sleep(delay); //sem_wait()和sem_trywait()都相当于P操作,二者的区别在于 //sem_wait()会阻塞进程,而sem_trywait()会立即返回 sem_wait(&avail); sem_wait(&mutex); printf("Producer: delay = %d\n",delay); if((len = write(fd,content,strlen(content)))==-1) { if(errno = EAGAIN) { printf("The FIFO has not been read yet!\n"); } } else { printf("write %d to the FIFO\n",len); } //sem_post()相当于V操作,信号量加1,唤醒等待进程 sem_post(&full); sem_post(&mutex); } pthread_exit(0); } void *customer(void *arg) { unsigned char buf[UNIT_SIZE]; int len; int delay; while(time(NULL)<end_time) { delay = (int)(rand()*DELAY_TIME_LEVELS/(RAND_MAX)/2.0)+1; sleep(delay); sem_wait(&full); sem_wait(&mutex); printf("\nCustomer: delay = %d\n",delay); memset(buf,0,UNIT_SIZE); if((len = read(fd,buf,UNIT_SIZE))==-1) { if(errno==EAGAIN) { printf("No data yet!\n"); } } else { printf("Read %s from FIFO\n",buf); } sem_post(&avail); sem_post(&mutex); } pthread_exit(0); } int main() { pthread_t pro_id,cus_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; } ret = sem_init(&mutex,0,1); ret += sem_init(&avail,0,BUFFER_SIZE); ret += sem_init(&full,0,0); if(ret!=0) { printf("Any semaphore initialization failed\n"); return ret; } pthread_create(&pro_id,NULL,producer,NULL); pthread_create(&cus_id,NULL,customer,NULL); pthread_join(pro_id,NULL); pthread_join(cus_id,NULL); close(fd); //unlink删除的是目录项,将文件链接计数减1,并没有真正的删除文件,可以 //用来作为临时文件 unlink(MYFIFO); }