实验九基于信号量机制的并发程序设计
完整课程设计源码及其报告查看:陈陈的操作系统课程设计
.
实验九 基于信号量机制的并发程序设计
1、实验目的
(1) 回顾操作系统进程、线程的有关概念,针对经典的同步、互斥、死锁与饥饿问题进行并发
程序设计与实现。
(2) 理解互斥体对象,利用互斥与同步操作编写读者-写者问题的并发程序,加深对 P (即semWait)、V(即 semSignal)原语以及利用 P、V 原语进行进程间同步与互斥操作的理解。
(3) 理解 Linux 支持的信息量机制,利用 IPC 的信号量系统调用编程实现哲学家进餐问题。
2、设计任务:
(1) 读者-写者问题的并发程序设计
(2) 哲学家进餐问题的并发程序设计
以上两个任务任选一个完成即可。
3、背景知识
(1)相关并发控制的 Windows API 函数请参考实验四。
(2)UINX/Linux 系统把信号量、消息队列和共享资源统称为进程间通信资源(IPC resource)。提供给用户的 IPC 资源是通过一组系统调用实现的。Unix/Linux 中可使用 IPC 中提供的 semget(),semop(),及 semctl()等信号量系统调用,它们的简介请查询实验三的背景知识部分,具体如何使用请自行进一步查询有关资料。
4、实验内容和要求
(1) 读者写者问题的并发程序设计
根据实验四中所熟悉的 P、V 原语对应的实际 Windows API 函数,并参考教材中读者-写者问题的算法原理,尝试利用 Windows API 函数实现第一类读者-写者问题(读者优先)。
(2)哲学家进餐问题的并发程序设计
使用 UINX/Linux 系统的系统调用 semget(),semop(),及 semctl()编制一个哲学家进餐问题(教材 P176-177)的程序。思路:为了便于操作和观察结果,用主程序创建一个信号量集(五个叉子信号量),然后先后 fork()五个哲学家子进程,使它们通过对信号量进行 P、V 操作并发地进行 thinking 与 eating.
以上两个实验内容任选一个完成即可。
实验源码:
#include<unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)
#define DELAY (rand()%5+1)
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
int semid;//信号量ID
int sem_p(int no)
{
struct sembuf sb={no,-1,0};
int ret=semop(semid,&sb,1);
if(ret==-1)ERR_EXIT("semop");
return ret;
}
void wait_for_2fork(int no)
{
int left=no;
int right=(no+1)%5;//拿右边的筷子
struct sembuf buf[2]={{left,-1,0},{right,-1,0}};//拿起筷子,因此第left,right信号量减一
semop(semid,buf,2);//P操作,若果能同时拿起两个筷子,就不用等待
}
void free_2fork(int no)
{
int left=no;
int right=(no+1)%5;
struct sembuf buf[2]={{left,1,0},{right,1,0}};//放下筷子,因此第left,right信号量加一
semop(semid,buf,2);//V操作,同时放下两只筷子
}
int philosephere(int no)
{
srand(getpid());
for(;;)
{
printf("%d is thinking\n",no);
sleep(DELAY);
printf("%d is hungry\n",no);
wait_for_2fork(no);
printf("%d is eating\n",no);
sleep(DELAY);
free_2fork(no);
}
}
int main(int argc,char *argv[])
{
union semun su;
su.val=1;
semid=semget(IPC_PRIVATE,5,IPC_CREAT|0666);//因为是父子进程通信,可以设置为IPC_PRIVATE,五个人,因此管理五个信号量
if(semid==-1)ERR_EXIT("semget");
for(int i=0;i<5;i++)semctl(semid,i,SETVAL,su); //将5个信号量分别初始化为1
int no=0;
int i=0;
pid_t pid;
for(i=1;i<5;i++)
{
pid=fork();//产生5个进程
if(pid==-1)ERR_EXIT("fork");
if(pid==0)
{
no=i;
break;//必须break,否则子进程会创建出新的进程
}
}
// printf("no=%d\n",no);
philosephere(no);
return 0;
}
实验结果截图及其分析:
更多课程设计源码请进主页查看搜索:陈陈不会敲代码
完整课程设计报告请下载:陈陈的操作系统课程设计源码及其报告
完整报告包含以下内容的源码以及实验报告:
资源展示如下: