洗尘斋

三悬明镜垂鸿韵,九撩清泉洗尘心

常用链接

统计

最新评论

信号量与PV操作

//信号量与PV操作的一个例子,模拟借书还书操作,共4个用户,每用户最多借15本书,书库共40本书,在书库没书时,该用户处于睡眠等待状态,直到有其他用户还书,若所有用户均处于等待状态,则产生了死锁

int Semget(key_t semkey,int nsems,int semflgs);
bool P(int sid,int semnum,int n);
bool V(int sid,int semnum,int n);
void sig_usr1(int);
static int pid[4];
int main(int argc,char **argv)
{
    
int semid;
    
if((semid=Semget(4446,1,IPC_CREAT|IPC_EXCL|0666))==-1)exit(-1);
    
if(semctl(semid,0,SETVAL,40)==-1)perr_exit("semctl");   //书的总量

    
int book,sleeptime;
    
int borrow;
    
for(int i=0;i<4;i++){      //4个用户
        pid[i]
=fork();
        
if(pid[i]<0){perror("Fork");i--;}
        
else if(pid[i]==0){
            srand(time(NULL)
+i);
            book
=0;
            
while(1){
                sleeptime
=rand()%7;
                borrow
=sleeptime-3;   //每次最多借还3本
                
if(borrow>0&&borrow+book<=15)   //每人最多借15本
                {
                    
if(!P(semid,0,borrow))
                        
continue;
                    book
+=borrow;
                    cout
<<"User "<<i<<" borrow "<<borrow<<" books from libary,"
                        
<<"now it remains ";
                    
                    cout
<<semctl(semid,0,GETVAL,0)<<" books\n";
                    sleep(sleeptime);
                }
                
else if(borrow<0&&borrow+book>=0)
                {
                    
if(!V(semid,0,-borrow))continue;
                    book
+=borrow;
                    cout
<<"User "<<i<<" gives "<<-borrow<<" books back to libary,"
                        
<<"now it remains ";   //由于V与GETVAL并不是原子操作,此处可能打印错误
                                                //有可能在归还与取值之间,书被借出
                    
                    cout
<<semctl(semid,0,GETVAL,0)<<" books\n";
                    
                    sleep(sleeptime);
                }
            }
            
return 0;
        }
    }
    signal(SIGUSR1,sig_usr1);
    
while(1)usleep(1000);
    
return 0;
}

int Semget(key_t semkey,int nsems,int semflgs)
{
    
int semid;
    
if ((semid = semget(semkey, 00)) == -1) {  /* Semaphore does not exist - Create. */
        
if ((semid = semget(semkey,nsems,semflgs)) != -1)
            
return semid;
        
else if (errno == EEXIST) {
            
if((semid = semget(semkey, 00)) == -1) {
                perror(
"IPC error 1: semget"); return -1;
            }
        }
        
else {
            perror(
"IPC error 2: semget"); return -1;
        }
    }
    
return semid;
}

void sig_usr1(int sig)
{
    
for(int i=0;i<4;i++)
        kill(pid[i],SIGQUIT);
    kill(getpid(),SIGQUIT);
}

bool Semset(int sid,int semnum,int n)
{
    
struct sembuf sm;
    sm.sem_num
=semnum;
    sm.sem_op
=n;
    sm.sem_flg
=SEM_UNDO;
    
if(semop(sid,&sm,1)==-1){
        perror (
"semop");
        
return false;
    }
    
return true;
}

bool P(int sid,int semnum,int n)
{
    
return Semset(sid,semnum,-n);
}

bool V(int sid,int semnum,int n)
{
    
return Semset(sid,semnum,n);
}

以下是解决死锁之后的代码,主进程负责监测子进程,如果发生死锁,就发信号阻止某个进程,禁止其消费,只允许其生产,而若该子进程不能生产,则用信号通知父进程,让其另选其他进程阻止。而若子进程监测到资源可供消费,则向自身发信号,设置其为可消费状态。
int Semget(key_t semkey,int nsems,int semflgs);
bool P(int sid,int semnum,int n);
bool V(int sid,int semnum,int n);
void sig_usr1(int);
void sig_usr2(int);
#define MaxUser 5
static int pid[MaxUser];
volatile bool good=true;
static int lastdeny;
static int user;
#define SIGDENY    SIGUSR2+1
#define SIGALLOW    SIGUSR2
#define SIGNEXTDENY    SIGUSR2+2
int main(int argc,char **argv)
{
    
int semid;
    
if((semid=Semget(4446,1,IPC_CREAT|IPC_EXCL|0666))==-1)exit(-1);
    
if(semctl(semid,0,SETVAL,40)==-1)perr_exit("semctl");

    
int book,sleeptime;
    
int borrow;
    
for(user=0;user<MaxUser;user++){
        pid[user]
=fork();
        
if(pid[user]<0){perror("Fork");user--;}
        
else if(pid[user]==0){
            srand(time(NULL)
+user);
            book
=0;
            signal(SIGALLOW,sig_usr2);
            signal(SIGDENY,sig_usr2);
            
while(1){
                sleeptime
=rand()%6;
                borrow
=sleeptime-2;
                
if(!good &&semctl(semid,0,GETNCNT,0)<MaxUser-1)
                    kill(getpid(),SIGALLOW);
                
else if(borrow>0&&borrow+book<=15&&good)
                {
                    
if(!P(semid,0,borrow))
                        
continue;
                    book
+=borrow;
                    cout
<<"User "<<user <<" borrow "<<borrow<<" books from libary,"
                        
<<"now it remains ";
                    
                    cout
<<semctl(semid,0,GETVAL,0)<<" books\n";
                    sleep(sleeptime);
                }
                
else if(borrow<0&&borrow+book>=0)
                {
                    
if(!V(semid,0,-borrow))continue;
                    book
+=borrow;
                    cout
<<"User "<<user<<" gives "<<-borrow<<" books back to libary,"
                        
<<"now it remains ";
                    
                    cout
<<semctl(semid,0,GETVAL,0)<<" books\n";
                    
                    sleep(sleeptime);
                }
                
else if(!good&&book==0)    //cannot borrow and no book keeping
                {
                    kill(getpid(),SIGALLOW);
                    kill(getppid(),SIGNEXTDENY);    
//send signal to parent to deny some other user
                }

            }
            
return 0;
        }
    }
    signal(SIGUSR1,sig_usr1);
    signal(SIGNEXTDENY,sig_usr2);
    srand(time(NULL));
    
volatile int x=0;
    
int y=0;

    
while(1){        
        
if(semctl(semid,0,GETNCNT,0)>=MaxUser){    //deadlock appear
            while(pid[(x=rand()%MaxUser)]==lastdeny);
            kill((lastdeny
=pid[x]),SIGDENY);        //make some user cannot borrow
        }
        usleep(
1000);
        y
++;
        
if(y%1000==0){
            y
=0;
            cout
<<"\t\tMain Running\t\t"<<semctl(semid,0,GETNCNT,0)<<"waits\n";
        }
    }
    
return 0;
}

int Semget(key_t semkey,int nsems,int semflgs)
{
    
int semid;
    
if ((semid = semget(semkey, 00)) == -1) {  /* Semaphore does not exist - Create. */
        
if ((semid = semget(semkey,nsems,semflgs)) != -1)
            
return semid;
        
else if (errno == EEXIST) {
            
if((semid = semget(semkey, 00)) == -1) {
                perror(
"IPC error 1: semget"); return -1;
            }
        }
        
else {
            perror(
"IPC error 2: semget"); return -1;
        }
    }
    
return semid;
}

void sig_usr1(int sig)
{
    
for(int i=0;i<MaxUser;i++)
        kill(pid[i],SIGQUIT);
    kill(getpid(),SIGQUIT);
}

void sig_usr2(int sig)
{
    
if(sig==SIGALLOW){        //allow user  borrow book
        good=true;
        cout
<<"/*--------------------------User"<<user
            
<<" Allowed-----------------------*/"<<endl;
    }
    
else if(sig==SIGDENY){    //deny user borrow book
        good=false;
        cout
<<"/*---------------------------User"<<user
            
<<" Denied-----------------------*/"<<endl;
    }
    
else if(sig==SIGNEXTDENY){    //deny some user
        volatile int deny;
        
while(pid[deny=rand()%MaxUser]==lastdeny);
        kill((lastdeny
=pid[deny]),SIGDENY);
    }
}

bool Semset(int sid,int semnum,int n)
{
    
struct sembuf sm;
    sm.sem_num
=semnum;
    sm.sem_op
=n;
    sm.sem_flg
=SEM_UNDO;
    
if(semop(sid,&sm,1)==-1){
        cout
<<"/**********User "<<user<<" semop error:"
            
<<strerror(errno)<<"**************/"<<endl;
        
return false;
    }
    
return true;
}

bool P(int sid,int semnum,int n)
{
    
return Semset(sid,semnum,-n);
}

bool V(int sid,int semnum,int n)
{
    
return Semset(sid,semnum,n);
}

posted on 2007-09-20 14:21 芥之舟 阅读(5226) 评论(1)  编辑 收藏 引用 所属分类: unix

评论

# re: 信号量与PV操作 2009-03-04 16:16 0019B0

bool P(int sid,int semnum,int n)
{
return Semset(sid,semnum,-n);
}

bool V(int sid,int semnum,int n)
{
return Semset(sid,semnum,n);
}











  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理