【要求】所有练习题保留题目要求,在题目要求后面作答:
代码要求有注释,代码中适当标注关键代码为红色。
要有运行结果的截图。
每题最后应该有对程序的适当分析和总结!
注意格式排版,内容分析注意列条目,展开清楚地阐述。
1、实现多个进程之间互斥访问临界资源(进程个数不限,先写出PV操作的伪算法,然后进行算法实现)
#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 mutex;
char ch;
int main()
{
pid_t pid;
pid_t pids[2];
int i, j;
struct sembuf p, v;
mutex = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT); // 创建信号量
semctl(mutex, 0, SETVAL, 1); // 互斥信号量mutex赋初值为1
// 定义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;
for(i = 0;i <= 2; i++){
pid = fork();
if(pid == 0){ // 子进程
while(1){
printf("%d want to enter --WAIT\n",i);
semop(mutex, &p, 1); // 信号量操作的申请wait
printf("%d is in\n",i);
sleep(3);
semop(mutex, &v, 1); // 信号量操作的释放signal
printf("%d is out --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');
}
三个pid进程(i=0,1,2)互斥访问临界资源mutex,每次访问前申请信号量执行p操作,指令完成后释放信号量执行v操作;最后手动结束所有进程
2、不死锁的哲学家进餐问题(课本有3种解决方法,可以选择一种或多种,先写出PV操作的伪算法,然后进行算法实现)
#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;
// 调用库函数,进行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 roomnum = 0;
int chopstick[5];
char ch;
int main()
{
roomnum = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT); // 创建信号量
semctl(roomnum, 0, SETVAL, 4); // 至多只允许四个哲学家同时进餐
int i = 0;
pid_t pid;
pid_t pids[5];
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) // child process manager code
{
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);
sleep(5 - i);
printf("Philosopher %d ends 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 down left chopstick\n", i);
// 哲学家进餐结束,释放资源
V(roomnum);
printf("Philosopger %d out of the room\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');
}
3、三个进程P1、P2、P3互斥使用一个包含N个单元的缓冲区。P1每次用produe()产生一个正整数并用put()送入缓冲区某一空单元中;P2每次用getodd()从该缓冲区中取出一个奇数并用countodd()统计奇数个数;P3每次用geteven()从该缓冲区中取出一个偶数并用counteven()统计偶数个数。请用信号量机制实现这三个进程的同步和互斥活动,并说明所定义信号量的含义。(先写出PV操作的伪算法,然后进行算法实现)
//定义P(wait)、V(signal)操作
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;
}
// 使用信号量机制定义
semaphore mutex = 1; // 互斥访问缓冲区
semaphore empty = n; // 缓冲区中有n个单元
semaphore odd = 0; // 奇数个数初始化为0
semaphore even = 0; // 偶数个数初始化为0
void P1(){
while(true){
int num = produce();// 产生一个正整数num
p(empty); // 消耗掉一个空单元
p(mutex); // 申请访问缓冲区;
put(num);
v(mutex); // 释放缓冲区
if(num % 2 == 0) // 如果num为偶数向P3发出信号
v(even);
else // 如果num为奇数向P2发出信号
v(odd);
}
}
void P2(){
while(true){
p(odd); // 收到来自P1已产生奇数的信号
p(mutex); // 申请访问缓冲区
getodd(); // 从缓冲区中取出一个奇数
v(mutex); // 释放缓冲区
v(empty); // 释放一个空单元,向P1发出信号
countodd(); // 统计奇数个数
}
}
void P3(){
while(true){
p(even); // 收到来自P1已产生偶数的信号
p(mutex); // 申请访问缓冲区
geteven(); // 从缓冲区释放一个偶数
v(mutex); // 释放缓冲区
v(empty); // 释放一个空单元,向P1发出信号
counteven(); // 统计偶数个数
}
}