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');
}
- 三个进程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');
}