实验三 进程线程同步编程练习

1.实现多个进程之间互斥访问临界资源(进程个数不限,先写出PV操作的伪算法,然后进行算法实现)

创建信号量

semid=semget(IPC_PRIVATE,1,0666|IPC_CREAT);

信号量赋初值

semctl(semid,0,SETVAL,1);

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
int room = 0;
char ch;
int main(int argc,char argv[]) {
    pid_t pid;
    pid_t pids[2];
    int i=0;
    int j=0;
    struct sembuf sem_b;
    sem_b.sem_num=0;
    sem_b.sem_flg=SEM_UNDO;//操作标志SEM_UNDO,进程意外结束恢复信号量操作
//创建控制进入房间的信号量
room=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
//互斥信号量room赋初值为1
    semctl(room,0,SETVAL,1); // 设置信号集中的一个单独信号量的值     
 for (i=0;i<2;i++) {
        pid=fork();
        if (pid==0){
            while(1){
                printf("%d want to  enter room--WAIT\n",i);
                sem_b.sem_op = -1;//定义申请资源操作,操作数量为1个,负数表示P操作       ( # ) 
                semop(room,&sem_b,1);//此两句是信号量操作的申请wait           ( # )
                printf("%d is in room\n",i);            (*)
                sleep(3);                 
                sem_b.sem_op = 1;//定义释放资源操作,操作数量为1个,正数表示V操作           ( # )
                semop(room,&sem_b,1);//此两句是信号量操作的释放signal           ( # )
                printf("%d is out of room---SIGNAL OK\n",i);
            }//while
        } else{ pids[i]=pid;}
    }//for
do{
        ch=getchar();
        if (ch == 'q')
            for (i=0;i<2;i++)
                kill(pids[i],SIGTERM);//退出进程运行
    }while(ch != 'q');
} //main

 

 

如图所见,进程0,1,2在不断的进进出出,先请求,wait,0进程先进去,1,2在外面等待,等0出去之后1,2按等待顺序进入,这里的是2先等待的则2先进去了,0等待,2出去后,之前在外面等的1 再进去,最后1出,0进。

如果for(i=0;i<2;i++)则只有两个进程,0,1进程,就是0进程先申请房间,之后0进入,1在外面等待,0出1进,1出0进,两个进程之间就是简单互斥关系。

 

2.不死锁的哲学家进餐问题(课本有3种解决方法,可以选择一种或多种,先写出PV操作的伪算法,然后进行算法实现)

创建线程函数 —— pthread_create

终止线程 —— pthread_cancel、pthread_exit

线程等待 —— pthread_join

Semaphore chopstick[5]={1,1,1,1,1};//初始化信号量

Semaphore mutex=l;//设置取筷子信号量

Pi(){

while(1){

          wait(mutex);//等待提取信号量

          wait(chopstick[ i ]);//取左边筷子

          wait(chopstick[ ( i +1) %5] );//去右边筷子

          Eat;

          signal(chopstick[ i ]);//放回左边筷子

          signal(chopstick[ ( i +1) % 5] );//放回右边筷子

          signal(mutex);

          think;

      }

}

#include <stdio.h>
   #include <stdlib.h>
   #include <unistd.h>
   #include <sys/types.h>
   #include <sys/ipc.h>
   #include <sys/sem.h>
   #include <errno.h>
   #include <fcntl.h>
   #include <signal.h>
  int p(int sem_id)
  {
  struct sembuf sem_b;
  sem_b.sem_num = 0;
  sem_b.sem_op = -1;
  sem_b.sem_flg = SEM_UNDO;

  if(semop(sem_id,&sem_b,1) == -1)
  {
  fprintf(stderr, "P failed\n");
  return 0;
  }
  return 1;
  }

  int v(int sem_id)//将信号量操作封装到函数中,提高代码可读性
  {
  struct sembuf sem_b;
  sem_b.sem_num = 0;
  sem_b.sem_op = 1;
  sem_b.sem_flg = SEM_UNDO;

  if(semop(sem_id,&sem_b,1) == -1){
  fprintf(stderr, "v failed\n");
  return 0;
  }
  return 1;
  }

  int roomnum=0;
  char chopsticks[5];
  int main(int argc,int  *argv[])
 {pid_t pid;
  pid_t pids[5];
  int i;
  char ch;
  roomnum=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
  semctl(roomnum,0,SETVAL,4);
  for(i=0;i<5;i++)
  {chopsticks[i]=semget(IPC_PRIVATE,1,0666|IPC_CREAT);//设置chopsticks信号量用于控制对筷子的资源使用
  semctl(chopsticks[i],0,SETVAL,1);}//设置信号量(筷子数量)初值为1
  for(i=0;i<5;i++){
  pid=fork();
  if(pid==0){
  while(1){
  printf("p %d is thinking,he is not hungry\n",i);
  sleep(1);

  p(roomnum);
  printf("p %d is hungry,so he enters to room\n",i);

  p( chopsticks[i]);
  printf("p %d take the left chopsticks\n",i);

  p( chopsticks[(i+1)%5]);
  printf("p %d take the right chopsticks\n",i);

  printf("p %d is eating!\n",i);
  sleep(5-i);

  printf("p %d ends to eat\n",i);

  v( chopsticks[(i+1)%5]);
  printf("p %d put off the right chopsticks\n",i);

  v( chopsticks[i]);
  printf("p %d put off the left chopsticks\n",i);

  v(roomnum);
  printf("p %d goes out the room and thinks\n",i);}}
  else
  {pids[i]=pid;}}
  do{
  ch=getchar();
  if(ch=='q'){
  for(i=0;i<5;i++){
  kill(pids[i],SIGTERM);}}}
  while(ch!='q');
}

  1. 三个进程P1、P2、P3互斥使用一个包含N个单元的缓冲区。P1每次用produe()产生一个正整数并用put()送入缓冲区某一空单元中;P2每次用getodd()从该缓冲区中取出一个奇数并用countodd()统计奇数个数;P3每次用geteven()从该缓冲区中取出一个偶数并用counteven()统计偶数个数。请用信号量机制实现这三个进程的同步和互斥活动,并说明所定义信号量的含义先写出PV操作的伪算法,然后进行算法实现

PV操作伪算法:

Semaphore mutex=1;   //互斥信号量

Semaphore odd=0;    //奇数个数

Semaphore even=0;    //偶数个数

Semaphore empty=N; //N个缓冲区单元

P1()                           p2()                p3()

{while(1)                     {while(1)           {while(1)

{  p(empty);                   {p(odd);            { p(even);

 int x= Produce();             p(mutex);            p(mutex);

P(mutex);                       getodd();            geteven();

Put(x);                          countodd();          counteven();

V(mutex);                       v(mutex);            v(mutex);

 if(x%2!=0)//奇数               v(empty);             v(empty);

{v(odd);}                  }                    }

Else                      }                    }

{v(even);}//偶数

}

}

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
  int p(int sem_id){

  struct sembuf sem_b;
  sem_b.sem_num = 0;
  sem_b.sem_op = -1;
  sem_b.sem_flg = SEM_UNDO;

  if(semop(sem_id,&sem_b,1) == -1)
  {
  fprintf(stderr, "P failed\n");
  return 0;
  }
  return 1;
  }
 int v(int sem_id){

  struct sembuf sem_b;
  sem_b.sem_num = 0;
  sem_b.sem_op = 1;
  sem_b.sem_flg = SEM_UNDO;

  if(semop(sem_id,&sem_b,1) == -1){
  fprintf(stderr, "v failed\n");
  return 0;
  }
  return 1;
  }

  int n;
  int odd=0;
  int even=0;
  int empty=0;
  int full=0;
  int mutex=1;
  int countodd=0;
  int counteven=0;
  int main(int argc,int argv[])
 {
  int i;
  printf("请输入个数N的大小:\n");
  scanf("%d",&n);
  pid_t pid;
  pid_t pids[3];
  char ch;
  mutex=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
  semctl(mutex,0,SETVAL,1);

  empty=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
  semctl(empty,0,SETVAL,n);

  full=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
  semctl(full,0,SETVAL,0);

  odd=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
  semctl(odd,0,SETVAL,0);

  even=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
  semctl(even,0,SETVAL,0);

 for(i=0;i<3;i++)
  {
  pid=fork();
  if(pid==0&&i==0)
  {while(1)
  {p(mutex);
  p(empty);
  sleep(1);
  int m=rand();
  printf("放入随机数%d\n",m);
  if(m%2==0)
  {v(even);
  }
 if(m%2==1){
  v(odd);
  }
  v(mutex);
  v(full);
  }}

  if(pid==0&&i==1)
  {while(1)
  {p(full);
  p(mutex);
  sleep(1);
  p(odd);
  countodd+=1;
  printf("奇数个数为:%d\n",countodd);
  v(mutex);
  v(empty);
  }}

 if(pid==0&i==2)
 {while(1)
 {p(full);
 p(mutex);
 sleep(1);
 p(even);
 counteven+=1;
 printf("偶数个数为:%d \n",counteven);
 v(mutex);
 v(empty);
 }}
 else
 {pids[i]=pid;}}
 do{
  ch=getchar();
  if (ch == 'q'){
   for (i=0;i<3;i++){
     kill(pids[i],SIGTERM);}}
     }while(ch != 'q');
 }

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值