生产者消费者实验
程序实现了两个生产者和两个消费者的生产者消费者问题(当生产者消费者数目再多时加上几个子进程就可以了)为了防止程序陷入死循环,给生产者限定了生产次数,同时为了方便截图,将次数限定的比较少。下面是我的程序:
#include <semaphore.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <time.h>
#define BSIZE 8
typedef struct
{
int buffer[BSIZE];
sem_t lock;
sem_t nready;
sem_t nempty;
int index; //next to put, next get is index -1
}shared_t;
int get_one_item(shared_t *ptr)
{
int rval;
sem_wait(&ptr->nready);
sem_wait(&ptr->lock);
rval = ptr->buffer[--ptr->index];
sem_post(&ptr->lock);
sem_post(&ptr->nempty);
return rval;
}
int put_one_item(shared_t *ptr, int pval)
{
sem_wait(&ptr->nempty);
sem_wait(&ptr->lock);
ptr->buffer[ptr->index++] = pval;
sem_post(&ptr->lock);
sem_post(&ptr->nready);
return pval;
}
void err_quit(char *msg)
{
fprintf(stderr, "%s:%s/n", msg, strerror(errno));
exit(1);
}
int main (void)
{
pid_t pid;
int j;
shared_t *ptr;
ptr = mmap(NULL, sizeof(shared_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if ((int)ptr == -1)
err_quit("mmap error");
sem_init(&ptr->lock, 1, 1); /*shared between process, init-value = 1*/
sem_init(&ptr->nready, 1, 0);
sem_init(&ptr->nempty, 1, BSIZE);
setbuf(stdout, NULL);
//ptr->a=10;
pid = fork();
if (pid < 0)
err_quit("fork error");
else if (pid == 0)
{ /* child 第一个子进程,作为第一个消费者*/
sleep(2);
while (1)
{
printf("first process %d get value: %d/n", getpid(), get_one_item(ptr));
usleep(300*1000);
}
}
else
{
int pid1 = fork(); /*第二个子进程,作为第二个消费者*/
if (pid1< 0)
err_quit("fork second process error");
else if (pid1 ==0)
{
sleep(3);
while (1)
{
printf("second process %d get value: %d/n", getpid(), get_one_item(ptr));
usleep(300*1000);
}
}else
{
int pid2=fork();/*第三个子进程,作为生产者*/
if (pid2< 0)
err_quit("fork third process error");
else if(pid2==0)
{
srand(time(NULL));
int val=0;
for(j=0;j<5;j++)
// while(ptr->a)
{
val = 1+ rand() % 1000;
printf("third process put value: %d/n", put_one_item(ptr, val));
usleep(300*1000);
//(ptr->a)--;
}
}
else /*父进程,生产者*/
{
sleep(1);
srand(time(NULL));
int pval = 0;
//while(ptr->a)//
for( j=0;j<5;j++)
{
pval = 1+ rand() % 1000;
printf("parent put value: %d/n", put_one_item(ptr, pval));
usleep(300*1000);
//(ptr->a)--;
}
}
}
}
return 0;
}
实验结果的截图:
通过实验截图中可以看出来:
1、 由于消费者有一定的等待时间,所以生产者总是先于消费者。并且parent也有一定的等待时间,因此third process先执行;同时由于两个消费者等待的时间也不一样,因此两个消费者的消费能力并不一样。
2、 两个生产者都是执行了5次,但由于设置的buffer长度只有8,因此当缓冲区满了后,parent依然有两次没有执行,得等待消费者取走数据之后缓冲区不满再作这两次生产。
这也使我更加深了对共享缓冲区的认识。
3、 两个生产者的数据都是以时间作为种子的rand函数生成的。但在srand之前给parent加上了sleep(1),因此两个生产者进程产生的数据并不相同。
4、从截图中还可以看到,消费者没有完成之有一次命令执行结束的标志:kdlx@kdlx-desktop:~桌面$:这是因为但父进程parent结束之后命令就算结束了,子进程还可以在后台做自己的工作。
其实程序中还有不如意的地方,就是给两个生产者各自限定了生产次数,我原来的想法是让两个生产者一共生产10次。这就涉及到两个生产者进程间的共享变量问题。让一个共享变量控制两个进程的生产次数,每个进程生产一次都会给变量减1。想到缓冲区是共享的,我就考虑将缓冲区数组的最后一位拿出来作为这个共享的控制变量,但经过多次实验,开始两个生产者进程能够产生设定次数的数据,但当消费者进程启动后,third process进程又开始生产数据,但parent进程就不会再生产了。这样依然是不停的循环。这个问题还得再考虑一下……