操作系统实验(13)进程之间互斥访问临界资源、哲学家进餐

1、实现两个进程之间互斥访问临界资源

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<linux/sem.h>
int mutexid;
int main()
{
    
    
	int child, i, j;
	struct sembuf p, v;
	// 定义信号量,初值为1
	mutexid = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
	if (semctl(mutexid, 0, SETVAL, 1) == -1)
	{
    
    
		perror("semctl setval error");
	}

	// 定义p操作
	p.sem_num = 0;
	p.sem_op = -1;
	p.sem_flg = SEM_UNDO;

	// 定义v操作
	v.sem_num = 0;
	v.sem_op = 1;
	v.sem_flg = SEM_UNDO;

	child = fork();
	while (1)
	{
    
    
		if (child == -1)
		{
    
    
			printf("error");
		}
		// 父进程
		else if (child > 0)
		{
    
    
			i = 1;
			while (i <= 3)
			{
    
    
				sleep(1);
				semop(mutexid, &p, 1);
				printf("print in\n");
				sleep(1);
				printf("print out\n");
				semop(mutexid, &v, 1);
				i++;
			}
			wait(NULL);
			semctl(mutexid, IPC_RMID, 0);
			exit(0);
		}
		// 子进程
		else if (child == 0)
		{
    
    
			j = 1;
			while (j <= 3)
			{
    
    
				sleep(1);
				semop(mutexid, &p, 1);
				printf("child in\n");
				sleep(1);
				printf("child out\n");
				semop(mutexid, &v, 1);
				j++; 
			}
		}
	}
	return 0;
}

分析:
发现print in 和 print out之间和child in 、 child out之间都没有其他的输出,由此可见,两者进行之间不允许执行其他的操作。由于在输出print in 之前,进行了p操作,即申请资源,且存在一个信号量,所以其他进程只能等待,等print out之后进行v操作后可以执行其他进程。

2、不死锁的哲学家进餐问题

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<linux/sem.h>
int roomnum = 0;
int chopstick[5];
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;

	// 进行p操作
	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;

	// 进行v操作
	if (semop(sem_id, &sem_b, 1) == -1)
	{
    
    
		fprintf(stderr, "V failed\n");
		return 0;
	}
	return 1;
}
int main()
{
    
    
	roomnum = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
	semctl(roomnum, 0, SETVAL, 4); // 至多只允许四个哲学家同时进餐
	int i = 0;
	int pid;
	for (i = 0; i < 5; ++i)
	{
    
    
		chopstick[i] = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
		semctl(chopstick[i], 0, SETVAL, 1);
	}
	for (i = 0; i < 5; ++i)
	{
    
    
		pid = fork();
		if (pid == 0)
		{
    
    
			while (1)
			{
    
    
				// 哲学家在思考
				printf("Philosopher %d is thinking,No disterb\n",i);
				sleep(1);

				// 哲学家饿了,准备开始吃饭
				P(roomnum); // 
				printf("Philosopher %d is hungry,so he entered the room\n",i);

				// 哲学家拿左筷子
				P(chopstick[i]);
				printf("Philosopher %d pick up left chopstick\n", i);

				// 哲学家拿右筷子
				P(chopstick[(i + 1) % 5]);
				printf("Philosopher %d pick up right chopstick\n", i);

				// 有两只筷子后,开始进餐
				printf("Philosopher %d begins to eat!\n", i);

				// 吃完饭了,释放右筷子
				V(chopstick[(i + 1) % 5]);
				printf("Philosopher %d pick down right chopstick\n", i);

				// 吃完饭了,释放左筷子
				V(chopstick[i]);
				printf("Philosopher %d pick up left chopstick\n", i);

				// 哲学家进餐结束
				V(roomnum);
			}
		}
	}
	return 0;
}

分析:
哲学家进餐问题有三种解决方法:
方法一:最多只允许四位哲学家同时去拿做筷子,最终能保证至少有一位哲学家能进餐,并在用完后释放两只筷子供他人使用。
方法二:仅当哲学家的左右手都拿起时才允许进餐。换句话说,如果这个哲学家拿起左筷子没有右筷子能拿,拿就全部放下!
方法三:规定奇数号的哲学家先拿左筷子再拿右筷子,偶数好哲学家相反。
本题使用方法一解决,对四位哲学家初始4个信号量表示至多只允许四个哲学家同时进餐。创建五个子进程来表示五个哲学家的进餐情况,建立5个筷子的信号量,左右筷子同时存在即可进餐。
由于最多能有4个哲学家同时进餐,5个筷子。表示一定会有一个哲学家能有两只筷子,当该哲学家进餐完毕后,可以释放两只筷子给其他哲学家进餐使用,不会产生死锁。

猜你喜欢

转载自blog.csdn.net/qq_43656233/article/details/110471838
今日推荐