课程设计
课程设计名称:操作系统原理
专业班级:软件1301
学生姓名:理金龙
学号: 201316920126
指导教师:刘於勋
课程设计时间: 2015年7月6-11日
软件工程专业课程设计任务书
说明:本表由指导教师填写,由教研室主任审核后下达给选题学生,装订在设计(论文)首页
信息科学与工程学院课程设计成绩评价表
课程名称:操作系统原理
设计题目:编程模拟多进程共享临界资源
1 需求分析
1、要求产生至少3个进程:
2、两个进程模拟需要进入临界区的用户进程,当需要进入临界区时,显示:“进程x请求进入临界区…”,同时向管理进程提出申请;在临界区中等待一段随机时间,并显示:“进程x正在临界区…”;当时间结束,显示:“进程x退出临界区…”,同时向管理进程提出退出申请。
3、一个进程作为原语级管理进程,接受其他进程的临界区进入请求:如果允许进入,则设置相应变量,然后返回;如果不允许进入,则进入循环等待,直到允许为止;
4、对临界区的访问应遵循空闲让进、忙则等待、有限等待、让权等待的准则。
5、进程间通信可以采用信号、消息传递、管道或网络通信方式。
2 概要设计
2.1 其中包含两个重要的数据结构:
2.11 临界区:
Struct crform
{
Int sem; //临界区的信号量值sem
Int head; //临界区等待队列的头,指向的是最先到的进程
Int tail; //临界区等待队列的尾,指向的是进入等待队列的进程
Int duilie[20]; //存放的是等待的进程的信息,以便唤醒
待
}cr;
Cr.sem=1; //初始临界区信号量必须为一,因为只允许一个进程进入临界区
Cr.head=0; //初始时指向等待队列的第一个单元
Cr.tail=0;
2.12 消息队列:
Struct msgform
{
Long msgtype; //消息的类型,在取消息队列时用于区分哪些是该取的信息
Int mtext; //信息的内容,在这里是申请|退出进程的信息
};
2.2 进程创建和控制:fork()系统调用:
关键的语句:
int x,y;
while((x=fork())==-1);//创建子进程1
if(x==0)
{
//子进程1执行程序段
}
else
{
while((y=fork())==-1);
if(y==0)
{
//子进程2执行程序段
}
else
{
//父进程执行程序段
}
}
2.3设计流程图:
图1 用户进程流程图
图管理进程
图3 申请进入临界区处理子进程
图4 申请退出处理子程序
3 运行环境
3.1 linux操作系统
3.2 Gcc编译器
4 开发工具和编程语言
4.1 开发工具:
Gcc编译器
4.2 编程语言:
C语言
5 详细设计
子函数一:
void into() //申请进入临界区
{
struct msgform msg;
key_t hh=ftok("OSP.c",1);
int msgqid=msgget(hh,0666|IPC_CREAT);
cr.sem--; //一旦申请进入临界区就得减1
msgrcv(msgqid,&msg,4,1,0); //接收消息--申请进入进程发送的类型为1 msg.msgtype=(long)msg.mtext; //并把接收到的消息内容作为回馈消息的消息类型
if(cr.sem>=0) //判断此时进程的状态,sem>=0 可以获得临界区
{
if(msg.mtext==3)
printf("进程1:进入临界区\n");
else
printf("进程2:进入临界区\n");
msg.mtext=1; //现在允许进入,发送内容为1的消息给申请进程
msgsnd(msgqid,&msg,sizeof(int),0);
}
Else //到等待队列
{
if(msg.mtext==3)
printf("进程1:进入等待队列\n");
else
printf("进程2:进入等待队列\n");
cr.duilie[cr.tail]=msg.mtext;
cr.tail++;
if(cr.tail==20)
cr.tail=0;
msg.mtext=-1;
msgsnd(msgqid,&msg,sizeof(int),0); //若临界区忙,发送进入等待队列的消息给申请进入的进程
}
子函数二:
void out() //申请退出临界区
{
struct msgform msg;
key_t hh=ftok("OSP.c",1);
int msgqid=msgget(hh,0666|IPC_CREAT);
msgrcv(msgqid,&msg,4,2,0); //从消息队列上取下申请退出的消息
cr.sem++;
if(cr.tail!=cr.head) //查看等待队列中是否有等待进入临界区的队列
{
//有则唤醒等待队列中等待的进程,并允许申请退出的进程退出
if(msg.mtext==3)
printf("进程1:退出临界区\n");
else
printf("进程2:退出临界区\n");
msg.msgtype=msg.mtext;
msg.mtext=0;
msgsnd(msgqid,&msg,sizeof(int),0);
int pid2=cr.duilie[cr.head];
cr.head++;
if(cr.head==20)
cr.head=0;
msg.mtext=1;
msg.msgtype=pid2;
if(pid2==3)
printf("进程1:进入临界区\n");
else
printf("进程2:进入临界区\n");
msgsnd(msgqid,&msg,sizeof(int),0);
}
else //如果等待队列上没有等待进入临界区的进程,直接向申请退出的进程发送消息,允许退出
{
if(msg.mtext==3)
printf("进程1:退出临界区\n");
else
printf("进程2:退出临界区\n");
msg.msgtype=msg.mtext;
msg.mtext=0;
msgsnd(msgqid,&msg,sizeof(int),0);
}
}
6 调试分析
在作这个课题过程中遇到了主要的这样几个问题:
◆消息队列不能正常使用
错误原因1:消息队列没有建立成功
解决办法:在用消息队列之初先删除这个队列,然后再建立使用
错误原因2:取到的结果总出现错误,没有统一的消息类型
解决办法:定制统一的消息类型规则,依照规则使用消息类型
错误原因3:进程需要的消息已经被取走,使得进程停留在取消息这一步不向下执行
解决办法:是程序逻辑上的问题,仔细查看程序流程并操控好使得可以处于正常逻辑
◆申请到临界区退出临界区显示滞后(如有时会显示“进程一获得临界区”然
后“进程二退出临界区”)
错误原因: 在管理进程中已经将临界区状态修改为空闲,却没有显示哪个进程退出临界区,这个退出的信息必须等到子进程上cpu时才会显示出来,而这中间有别的进程上cpu执行申请的操作,就会获得临界区,就会显示“进程获得临界区”,在此后退出临界区的进程才上cpu显示“退出临界区”。
解决办法:将显示放到管理进程中,一旦有进程获得临界区或者退出临界区就做出显示。
7 测试结果
测试数据:1,0; 1,2
测试截图:
图5 开始界面
图6 主程序运行界面
图7 输入1,暂停运行
图8 输入0,程序继续运行
图9 输入2,程序退出运行
参考文献
[1] 任满杰等《操作系统原理实用教程》电子工业出版社 2006
[2] 汤子瀛《计算机操作系统》(修订版)西安电子科技大学出版社 2001
[3] 张尧学史美林《计算机操作系统教程》实验指导清华大学出版社 2000
[4] 罗宇等《操作系统课程设计》机械工业出版社 2005
[5] 赛奎春、张雨编著,《Visual C++ 工程应用与项目实践》,海洋出版社,2005.1
心得体会
这次操作系统课设给了我很大的启发和提高。一直以来自己我的编程基础不太好,常出现逻辑混乱,不注重细节问题,在这门课中我有了更深的理解;科学是不允许错误的,需要认真严谨的态度。也正是因为如此我才有了进步。理论联系实际,总会有更深刻的收获,通过这样的实际思考,动手修改操作,对理论有了深层次的理解,更加证实了理论,打消了心中不切实际的一些想法。慢慢的会形成自己的一个实际经验,为日后的工作学习打下心里和知识上的基础。小学期的课程真是紧张而又充实,确实是收获很多,心中也增加了几分自信,对未来的工作有更大的信息。
程序源代码(工程)第一部分:OSP.c #include
#include
#include
#include
#include
#include
#include "ran.h"
#define MSGKEY 898989
struct crform
{
int sem;
int head;
int tail;
int duilie[20];
}cr;
struct msgform
{
long msgtype;
int mtext;
};
void into();
void out();
int main(void) {
puts("***********************提示信息***********************\n");
puts("在程序运行过程中:\n");
puts("-------输入 0 继续运行程序\n");
puts("-------输入 1 暂停运行程序\n");
puts("-------输入 2 退出程序\n");
puts("*****************************************************\n");
int ppid=getpid();
cr.sem = 1;
cr.head=0;
cr.tail=0;
struct ShMe{
int num;
int flags;
int p1;
int p2;
};
int shmid=shmget(IPC_PRIVATE,1024,0666|IPC_CREAT);
if(shmid==-1){
printf("共享内存区创建错误-----\n");
exit(0);
}
pid_t id = fork();
if (id<0) {
printf("新进程创建错误!! 2秒后自动退出。。。。。\n");
sleep(2);
exit(0);
}else if (id==0) {
pid_t id2 = fork();
if(id2<0){
printf("新进程创建错误!! 2秒后自动退出。。。。。\n");
sleep(2);
exit(0);
}else if (id2==0) {
struct msgform msg;
key_t hh=ftok("OSP.c",1);
int msgqid=msgget(hh,0666|IPC_CREAT);
struct ShMe * addr;
addr=(struct ShMe*)shmat(shmid,0,0);
if(addr==(struct ShMe*)-1)
printf("映射内存错误1------\n");
int flags=0;
flags=addr->flags;
(*addr).p1=getpid();
while(flags==1||flags==0){
if(flags==0){
int q=10;
msg.mtext=3;
msg.msgtype=1;
printf("进程1: 申请进入临界区\n");
msgsnd(msgqid,&msg,sizeof(int),0);
kill(ppid,10);
while(q>0)
{
msgrcv(msgqid,&msg,sizeof(int),3,0);
int m=msg.mtext;
if(m==1)
{
printf("进程1: 进入共享内存区\n");
int ny=addr->num;
int dg=rannum();
int uh=0;
for(uh=0;uh ny++; } ny=ny%(99999-10000+1)+10000; (*addr).num=ny; msg.msgtype=2; msg.mtext=3; printf("进程1: 申请退出临界区\n"); msgsnd(msgqid,&msg,sizeof(int),0); kill(ppid,12); continue; } else { if(m==-1) { q--; } else { if(m==0) { int bb=rannum()%5; sleep(bb); flags=addr->flags; break; } } } } }else{