当前位置: 技术问答>linux和unix
生产者消费者问题--进程并发性体现得不太好,请帮我看看...
来源: 互联网 发布时间:2016-01-26
本文导语: 在Qt3.0下进行的开发,主要代码如下: #include #include #include #include #include #include #include #include #include /* pv_slot函数用信号量实现生产者和消费者的pv操作. */ void sem::pvSlot() { int sem_set_id; ...
在Qt3.0下进行的开发,主要代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*
pv_slot函数用信号量实现生产者和消费者的pv操作.
*/
void sem::pvSlot()
{
int sem_set_id;
int rc,child_pid;
QString str;
sem_set_id=semget(290,6,IPC_CREAT|0600);
if(sem_set_id==-1) {QMessageBox::information( this, "error",tr("创建失败"),QMessageBox::Ok);exit(-1); }
rc=semctl(sem_set_id,0,SETVAL,1); //设置互斥信号量初值
if(rc==-1) {QMessageBox::information( this, "error",tr("设置失败"),QMessageBox::Ok);exit(-1);}
rc=semctl(sem_set_id,1,SETVAL,0); //设置满缓冲池初值
if(rc==-1) {QMessageBox::information( this, "error",tr("设置失败"),QMessageBox::Ok); exit(-1);}
rc=semctl(sem_set_id,2,SETVAL,20); //设置空缓冲池初值
if(rc==-1) {QMessageBox::information( this, "error","设置失败",QMessageBox::Ok); exit(-1);}
rc=semctl(sem_set_id,3,SETVAL,1); //设置通知对方退出信号量的初值
if(rc==-1) {QMessageBox::information( this, "error","设置失败",QMessageBox::Ok); exit(-1);}
rc=semctl(sem_set_id,4,SETVAL,0); //设置生产产品数初值
if(rc==-1) {QMessageBox::information( this, "error","设置失败",QMessageBox::Ok); exit(-1);}
rc=semctl(sem_set_id,5,SETVAL,0); //设置消费产品数初值
if(rc==-1) {QMessageBox::information( this, "error","设置失败",QMessageBox::Ok); exit(-1);}
child_pid=fork(); //创建子进程
switch(child_pid){
/*
子进程--消费者.
*/
case -1:exit(-1);
case 0: while(semctl(sem_set_id,3,GETVAL)){
cwait(sem_set_id,1); //同步p操作
cwait(sem_set_id,0); //互斥p操作
if(!semctl(sem_set_id,3,GETVAL)) exit(0);
csignal(sem_set_id,5);
c->setText(str.setNum(semctl(sem_set_id,5,GETVAL)));
p->setText(str.setNum(semctl(sem_set_id,4,GETVAL)));
b->setText(str.setNum(semctl(sem_set_id,1,GETVAL))+"/20");
switch( QMessageBox::information( this, "continue",tr("希望继续消费吗?"),
QMessageBox::Yes, QMessageBox::No)){
case QMessageBox::Yes:
c->setText(str.setNum(semctl(sem_set_id,5,GETVAL)));
b->setText(str.setNum(semctl(sem_set_id,1,GETVAL))+"/20");
break;
case QMessageBox::No:
semctl(sem_set_id,3,SETVAL,0);
break;
}
csignal(sem_set_id,0); //互斥v操作
csignal(sem_set_id,2); //同步v操作
}
// exit(0);
/*
父进程--生产者.
*/
default: while(semctl(sem_set_id,3,GETVAL)){
cwait(sem_set_id,2);
cwait(sem_set_id,0);
if(!semctl(sem_set_id,3,GETVAL)) exit(0);
csignal(sem_set_id,4);
c->setText(str.setNum(semctl(sem_set_id,5,GETVAL)));
p->setText(str.setNum(semctl(sem_set_id,4,GETVAL)));
b->setText(str.setNum(20-semctl(sem_set_id,2,GETVAL))+"/20");
switch( QMessageBox::information( this, "continue",tr("希望继续生产吗?"),
QMessageBox::Yes, QMessageBox::No)){
case QMessageBox::Yes:
p->setText(str.setNum(semctl(sem_set_id,4,GETVAL)));
b->setText(str.setNum(20-semctl(sem_set_id,2,GETVAL))+"/20");
break;
case QMessageBox::No:
semctl(sem_set_id,3,SETVAL,0);
break;
}
csignal(sem_set_id,0);
csignal(sem_set_id,1);
}
// exit(0);
}
}
//v操作
void sem::csignal( int sem_set_id, int i )
{
struct sembuf sem_op;
sem_op.sem_num=i;
sem_op.sem_op=1;
sem_op.sem_flg=0;
semop(sem_set_id,&sem_op,1);
return;
}
//p操作
void sem::cwait( int sem_set_id, int i )
{
struct sembuf sem_op; //定义sem_op结构
sem_op.sem_num=i; //信号量集的某个信号量
sem_op.sem_op=-1; //负数代表占用资源,资源数量-1
sem_op.sem_flg=0; //标志位
semop(sem_set_id,&sem_op,1); //对信号量i进行一次操作
return;
}
相关说明:
生产者-消费者问题是一个著名的进程同步问题。它描述的是:有一个生产者进程在生产消息,并将此消息提供给消费者进程去消费。为使生产者进程和消费者进程能并发执行,在它们之间设置了一个具有20个缓冲区的缓冲池,生产者进程可将它所生产的消息放入一个缓冲区中,消费者进程可从一个缓冲区中取得一个消息消费。尽管生产者进程和消费者进程,都是以异步方式运行的,但它们之间必须保持同步,既不允许消费者进程到一个空缓冲区去取消息,也不允许生产者进程向一个已装有消息且未被取走消息的缓冲区中投放消息。
利用进程通信机制中的信号量机制的系统调用实现缓冲区和互斥信号以及对他们的操作。
信号量机制的系统调用有:
创建信号量数组:
sys_semget (key_t key, int nsems, int semflg)
调用接口为:
semget(key_t key, int nsems, int semflg)
操作信号量数组:
sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
调用接口为:
semop (int semid, struct sembuf *tsops, unsigned nsops)
设置信号量数组属性:
sys_semctl (int semid, int semnum, int cmd, union semun arg)
调用接口为:semctl (int semid, int semnum, int cmd, union semun arg)
利用sys_semget创建一个有6个信号量的信号量数组,分别表示互斥信号量、满缓冲区、空缓冲区、生产产品数、消费产品数以及一个生产者和消费者进程用来互相通知对方退出的信号量,利用sys_semctl设置6个信号量的初值,分别为1、0、20、0、0、1。定义函数cwait代表P操作,函数csignal代表V操作。在类Pvslot中定义一个方法pv()完成生产者-消费者过程的演示。
为了用图形化界面显示生产者-消费者的同步过程,用的是QtDesigner开发工具,定义的主框体为sem。图形界面包括一个开始按钮,这个按钮触发pv()函数,这个函数实现生产者-消费者问题的演示,一个显示生产产品数的文本框,一个显示消费产品数的文本框,一个显示缓冲区情况的文本框。当按下开始按钮时,开始进行过程演示,生产者进程与消费者进程随机对缓冲池进行请求操作,先得到互斥信号量的进程先操作;有一个原则:缓冲池空的时候,只有生产者进程进行生产;缓冲池满的时候,只有消费者进行消费。为了便于显示每一个生产和消费的操作,在进入生产进程或者消费进程的临界区时,都显示一个对话框,表示现在处于哪个进程,并询问是继续演示还是退出。
我的问题:
现在运行结果经常是生产者把缓冲池填满消费者才去消费,消费者把缓冲池取空,生产者才去生产。偶尔会出现生产者没有填满缓冲池,消费者抢到临界区的现象。这样一来,进程的并发性表现得不好,请问如何改进?谢谢!
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*
pv_slot函数用信号量实现生产者和消费者的pv操作.
*/
void sem::pvSlot()
{
int sem_set_id;
int rc,child_pid;
QString str;
sem_set_id=semget(290,6,IPC_CREAT|0600);
if(sem_set_id==-1) {QMessageBox::information( this, "error",tr("创建失败"),QMessageBox::Ok);exit(-1); }
rc=semctl(sem_set_id,0,SETVAL,1); //设置互斥信号量初值
if(rc==-1) {QMessageBox::information( this, "error",tr("设置失败"),QMessageBox::Ok);exit(-1);}
rc=semctl(sem_set_id,1,SETVAL,0); //设置满缓冲池初值
if(rc==-1) {QMessageBox::information( this, "error",tr("设置失败"),QMessageBox::Ok); exit(-1);}
rc=semctl(sem_set_id,2,SETVAL,20); //设置空缓冲池初值
if(rc==-1) {QMessageBox::information( this, "error","设置失败",QMessageBox::Ok); exit(-1);}
rc=semctl(sem_set_id,3,SETVAL,1); //设置通知对方退出信号量的初值
if(rc==-1) {QMessageBox::information( this, "error","设置失败",QMessageBox::Ok); exit(-1);}
rc=semctl(sem_set_id,4,SETVAL,0); //设置生产产品数初值
if(rc==-1) {QMessageBox::information( this, "error","设置失败",QMessageBox::Ok); exit(-1);}
rc=semctl(sem_set_id,5,SETVAL,0); //设置消费产品数初值
if(rc==-1) {QMessageBox::information( this, "error","设置失败",QMessageBox::Ok); exit(-1);}
child_pid=fork(); //创建子进程
switch(child_pid){
/*
子进程--消费者.
*/
case -1:exit(-1);
case 0: while(semctl(sem_set_id,3,GETVAL)){
cwait(sem_set_id,1); //同步p操作
cwait(sem_set_id,0); //互斥p操作
if(!semctl(sem_set_id,3,GETVAL)) exit(0);
csignal(sem_set_id,5);
c->setText(str.setNum(semctl(sem_set_id,5,GETVAL)));
p->setText(str.setNum(semctl(sem_set_id,4,GETVAL)));
b->setText(str.setNum(semctl(sem_set_id,1,GETVAL))+"/20");
switch( QMessageBox::information( this, "continue",tr("希望继续消费吗?"),
QMessageBox::Yes, QMessageBox::No)){
case QMessageBox::Yes:
c->setText(str.setNum(semctl(sem_set_id,5,GETVAL)));
b->setText(str.setNum(semctl(sem_set_id,1,GETVAL))+"/20");
break;
case QMessageBox::No:
semctl(sem_set_id,3,SETVAL,0);
break;
}
csignal(sem_set_id,0); //互斥v操作
csignal(sem_set_id,2); //同步v操作
}
// exit(0);
/*
父进程--生产者.
*/
default: while(semctl(sem_set_id,3,GETVAL)){
cwait(sem_set_id,2);
cwait(sem_set_id,0);
if(!semctl(sem_set_id,3,GETVAL)) exit(0);
csignal(sem_set_id,4);
c->setText(str.setNum(semctl(sem_set_id,5,GETVAL)));
p->setText(str.setNum(semctl(sem_set_id,4,GETVAL)));
b->setText(str.setNum(20-semctl(sem_set_id,2,GETVAL))+"/20");
switch( QMessageBox::information( this, "continue",tr("希望继续生产吗?"),
QMessageBox::Yes, QMessageBox::No)){
case QMessageBox::Yes:
p->setText(str.setNum(semctl(sem_set_id,4,GETVAL)));
b->setText(str.setNum(20-semctl(sem_set_id,2,GETVAL))+"/20");
break;
case QMessageBox::No:
semctl(sem_set_id,3,SETVAL,0);
break;
}
csignal(sem_set_id,0);
csignal(sem_set_id,1);
}
// exit(0);
}
}
//v操作
void sem::csignal( int sem_set_id, int i )
{
struct sembuf sem_op;
sem_op.sem_num=i;
sem_op.sem_op=1;
sem_op.sem_flg=0;
semop(sem_set_id,&sem_op,1);
return;
}
//p操作
void sem::cwait( int sem_set_id, int i )
{
struct sembuf sem_op; //定义sem_op结构
sem_op.sem_num=i; //信号量集的某个信号量
sem_op.sem_op=-1; //负数代表占用资源,资源数量-1
sem_op.sem_flg=0; //标志位
semop(sem_set_id,&sem_op,1); //对信号量i进行一次操作
return;
}
相关说明:
生产者-消费者问题是一个著名的进程同步问题。它描述的是:有一个生产者进程在生产消息,并将此消息提供给消费者进程去消费。为使生产者进程和消费者进程能并发执行,在它们之间设置了一个具有20个缓冲区的缓冲池,生产者进程可将它所生产的消息放入一个缓冲区中,消费者进程可从一个缓冲区中取得一个消息消费。尽管生产者进程和消费者进程,都是以异步方式运行的,但它们之间必须保持同步,既不允许消费者进程到一个空缓冲区去取消息,也不允许生产者进程向一个已装有消息且未被取走消息的缓冲区中投放消息。
利用进程通信机制中的信号量机制的系统调用实现缓冲区和互斥信号以及对他们的操作。
信号量机制的系统调用有:
创建信号量数组:
sys_semget (key_t key, int nsems, int semflg)
调用接口为:
semget(key_t key, int nsems, int semflg)
操作信号量数组:
sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
调用接口为:
semop (int semid, struct sembuf *tsops, unsigned nsops)
设置信号量数组属性:
sys_semctl (int semid, int semnum, int cmd, union semun arg)
调用接口为:semctl (int semid, int semnum, int cmd, union semun arg)
利用sys_semget创建一个有6个信号量的信号量数组,分别表示互斥信号量、满缓冲区、空缓冲区、生产产品数、消费产品数以及一个生产者和消费者进程用来互相通知对方退出的信号量,利用sys_semctl设置6个信号量的初值,分别为1、0、20、0、0、1。定义函数cwait代表P操作,函数csignal代表V操作。在类Pvslot中定义一个方法pv()完成生产者-消费者过程的演示。
为了用图形化界面显示生产者-消费者的同步过程,用的是QtDesigner开发工具,定义的主框体为sem。图形界面包括一个开始按钮,这个按钮触发pv()函数,这个函数实现生产者-消费者问题的演示,一个显示生产产品数的文本框,一个显示消费产品数的文本框,一个显示缓冲区情况的文本框。当按下开始按钮时,开始进行过程演示,生产者进程与消费者进程随机对缓冲池进行请求操作,先得到互斥信号量的进程先操作;有一个原则:缓冲池空的时候,只有生产者进程进行生产;缓冲池满的时候,只有消费者进行消费。为了便于显示每一个生产和消费的操作,在进入生产进程或者消费进程的临界区时,都显示一个对话框,表示现在处于哪个进程,并询问是继续演示还是退出。
我的问题:
现在运行结果经常是生产者把缓冲池填满消费者才去消费,消费者把缓冲池取空,生产者才去生产。偶尔会出现生产者没有填满缓冲池,消费者抢到临界区的现象。这样一来,进程的并发性表现得不好,请问如何改进?谢谢!
|
没qt环境,你能不能改成命令行的。
我搞了个简单的,semid的各个含义跟你的一样。
}else if( pid == 0 ){
srand( time(NULL) );
while( 1 ){
sleep( rand() % 3 );
cwait( semid, 1 );
cwait( semid, 0 );
printf( "Consumer: %d n", ++x );
csignal( semid, 0 );
csignal( semid, 2 );
}
exit( 0 );
}
srand( time(NULL) );
while( 1 ){
sleep( rand() % 3 );
cwait( semid, 2 );
cwait( semid, 0 );
printf( "Producter: %d n", ++x );
csignal( semid, 0 );
csignal( semid, 1 );
}
semctl( semid, 0, IPC_RMID );
我搞了个简单的,semid的各个含义跟你的一样。
}else if( pid == 0 ){
srand( time(NULL) );
while( 1 ){
sleep( rand() % 3 );
cwait( semid, 1 );
cwait( semid, 0 );
printf( "Consumer: %d n", ++x );
csignal( semid, 0 );
csignal( semid, 2 );
}
exit( 0 );
}
srand( time(NULL) );
while( 1 ){
sleep( rand() % 3 );
cwait( semid, 2 );
cwait( semid, 0 );
printf( "Producter: %d n", ++x );
csignal( semid, 0 );
csignal( semid, 1 );
}
semctl( semid, 0, IPC_RMID );