Chinaunix首页 | 论坛 | 博客
  • 博客访问: 305353
  • 博文数量: 47
  • 博客积分: 2026
  • 博客等级: 大尉
  • 技术积分: 1620
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-25 09:34
文章分类

全部博文(47)

文章存档

2009年(8)

2008年(39)

我的朋友

分类: LINUX

2008-11-25 23:07:45

//信号量与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);
}
阅读(2229) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~