Linux操作系统课程设计


中国地质大学(武汉)计算机学院计算机科学与技术专业本科生《操作系统概论》课程设计(作记录)。

1. 课程设计要求

  1. 按时参加上机实习,不得旷课、迟到、早退。
  2. 每个学生需在 Linux 下用 C 语言完成六道上机实习题。
  3. 每个学生需独立完成上机实习,不得相互抄袭。如发现抄袭者和被抄袭者成绩均不及格。
  4. 每个学生需在实习结束一周内将实习报告和源程序提交到班级学习委员,再由学习委员打包发到老师的邮箱,用于检查是否存在抄袭现象,邮件中请注明学生的班级和姓名。
  5. 每个学生需在实习结束一周内提交纸质实习报告一份。应包括如 下内容: 1)课程设计题目 2)程序功能及设计思路 3)数据结构及算法设计 4)程序运行情况 5)编程中遇到的困难及解决方法、实习心得或良好建议。

2. 评分

  1. 考勤占 20%,上机验收占 40%,实习报告占 40%。
  2. 抄袭程序者和被抄袭程序者,课程设计成绩不及格。
  3. 抄袭报告者和被抄袭报告者,课程设计成绩不及格。前六次上机每次完成一道实习题,最后两次上机组织验收。

3. 上机时间地点

  • 17 周 (12 月 25-29 日)周二下午、周四下午、周五上午,晚上。
  • 18 周 (元月 1-5 日)周二下午、周三下午,晚上 。
  • 前 7 次地点:12 班在 313 机房(Fedora) 34 班在 413 机房(Ubuntu)
  • 最后一次上机: 12 班:18 周周四 晚上 34 班:18 周周五 晚上

地点:313 机房(Fedora) 上午 8:30-11:30 下午 2:00-5:00 晚上 6:30-9:30

开机时进入 Linux 系统,默认使用用户名:suer,密码:123456。若默认密码登录不了,可能是被同学修改过了,换一台电脑使用。请同学们千万不要修改系统登录密码。若有同学自己的笔记本电脑已经装了 Linux,欢迎自带电脑上机实习。

4. 每次上机实习前先自学预备知识,并在作业本上编写初步的源程序。

5. 课程设计题目课程设计分六个实验,具体如下

5.1 实验 1:作业调度

5.1.1 实验目的

  1. 对作业调度的相关内容作进一步的理解。
  2. 明白作业调度的主要任务。
  3. 通过编程掌握作业调度的主要算法。

5.1.2 实验内容

1、假设系统中可同时运行两道作业,给出每道作业的到达时间和运行时间,如下表所示:

作业名 A B C D E F G H I J
到达时间 0 2 5 7 12 15 4 6 8 10
运行时间 10 20 30 40 8 8 20 10 12 7

2、分别用先来先服务算法、短作业优先和响应比高者优先三种算法给出作业的调度顺序。

3、计算每一种算法的平均周转时间及平均带权周转时间并比较不同算法的优劣。

5.1.3 预备知识

  1. 响应比=等待时间/运行时间+1

  2. 周转时间=完成时间-到达时间 带权周转时间=周转时间/运行时间

5.1.4 源代码

#include <iostream>
#include <string>
#include <fstream>
#include <vector>using namespace std;struct Work
{char name;//作业名称double arrive;//到达时间点double run;//运行时间Work() {}Work(char n, double a, double t) :name(n), arrive(a), run(t) {}Work operator =(const Work &rhs){this->name = rhs.name;this->arrive = rhs.arrive;this->run = rhs.run;return *this;}
};vector<Work> gWork;//存放所有的作业信息
double sum_turn, sum_dturn;//总的周转时间和带权周转时间void ReadFile();//从txt文本中读取作业调度信息
void Output();//输出结果
void Dispatch();//调度过程中的数据处理
void Fcfs();//先来先服务算法
void Sjf();//短作业优先算法
void Hrf();//高响应比优先算法int main()
{ReadFile();cout << "先来先服务算法:" << endl;Fcfs();cout << "短作业优先算法:" << endl;Sjf();cout << "高响应比算法:" << endl;Hrf();return 0;
}//从文本中读取作业调度信息
void ReadFile()
{ifstream ifile;ifile.open("/home/jason/文档/OS/Pro_1/data.txt");if (!ifile){cout << "文件打开失败!" << endl;return;}char name;double arrive;double run;while (ifile >> name >> arrive >> run){gWork.push_back(Work(name, arrive, run));}ifile.close();
}//输出结果
void Output()
{cout << "作业调度顺序:";for (unsigned i = 0; i < gWork.size(); ++i)cout << gWork[i].name << " ";cout << endl;cout << "平均周转时间:" << sum_turn / gWork.size() << endl;cout << "平均带权周转时间:" << sum_dturn / gWork.size() << endl;cout << endl;
}//调度过程中的数据处理
void Dispatch()
{unsigned n = static_cast<unsigned>(gWork.size());double t1 = 0, t2 = 0;//同时运行两个作业,设置两个时间轴以记录各个作业完成情况sum_turn = 0;//初始化sum_dturn = 0;for (unsigned i = 0; i < n; ++i){if (t1 > t2)//表明t1有作业时t2空闲{if (t2 < gWork[i].arrive)t2 += gWork[i].arrive;t2 = t2 + gWork[i].run;sum_turn = sum_turn + t2 - gWork[i].arrive;sum_dturn = sum_dturn + (t2 - gWork[i].arrive) / gWork[i].run;}else{if (t1 < gWork[i].arrive)t1 += gWork[i].arrive;t1 = t1 + gWork[i].run;sum_turn = sum_turn + t1 - gWork[i].arrive;sum_dturn = sum_dturn + (t1 - gWork[i].arrive) / gWork[i].run;}}
}//先来先服务算法
void Fcfs()
{unsigned n = static_cast<unsigned>(gWork.size());//按照来到的时间点排序,升序Work temp;for (unsigned i = 0; i < n; ++i){for (unsigned j = 0; j < n - i - 1; ++j){if (gWork[j].arrive > gWork[j + 1].arrive){temp = gWork[j + 1];gWork[j + 1] = gWork[j];gWork[j] = temp;}}}Dispatch();Output();
}//短作业优先算法
void Sjf()
{unsigned n = static_cast<unsigned>(gWork.size());//按照作业运行时间的长短排序,升序Work temp;for (unsigned i = 0; i < n; ++i){for (unsigned j = 0; j < n - i - 1; ++j){if (gWork[j].run > gWork[j + 1].run){temp = gWork[j + 1];gWork[j + 1] = gWork[j];gWork[j] = temp;}}}Dispatch();Output();
}//高响应比优先算法
void Hrf()
{int n = static_cast<int>(gWork.size());//按照来到的时间点排序,升序Work temp;for (int i = 0; i < n; ++i){for (int j = 0; j < n - i - 1; ++j){if (gWork[j].arrive > gWork[j + 1].arrive){temp = gWork[j + 1];gWork[j + 1] = gWork[j];gWork[j] = temp;}}}vector<Work> temp_work;for (int i = 0; i < n; ++i)temp_work.push_back(gWork[i]);gWork.clear();sum_turn = 0;//初始化sum_dturn = 0;double t1 = 0, t2 = 0;//同时运行两个作业,设置两个时间轴以记录各个作业完成情况int i = 0, flag = 0;n = static_cast<int>(temp_work.size());double max_rate = 0, rate = 0;//运行第一个作业for (i = 0; i < n; ++i){//rate = wait / run + 1rate = (temp_work[n - 1].arrive - temp_work[i].arrive) / temp_work[i].run + 1;if (max_rate < rate){max_rate = rate;flag = i;}}t1 = temp_work[flag].arrive + temp_work[flag].run;sum_turn = t1 - temp_work[flag].arrive;sum_dturn = (t1 - temp_work[flag].arrive) / temp_work[flag].run;gWork.push_back(temp_work[flag]);temp_work.erase(temp_work.begin() + flag);//已经运行的作业要删去//运行剩下的作业while (!temp_work.empty()){n = static_cast<int>(temp_work.size());flag = 0;max_rate = 0;rate = 0;if (t1 > t2)//表明t1有作业时t2空闲{//运行第二个作业if (t2 == 0){for (i = 0; i < n; ++i){//rate = wait / run + 1rate = (temp_work[n - 1].arrive - temp_work[i].arrive) / temp_work[i].run + 1;if (max_rate < rate){max_rate = rate;flag = i;}}t2 = temp_work[flag].arrive + temp_work[flag].run;sum_turn = t2 - temp_work[flag].arrive;sum_dturn = (t2 - temp_work[flag].arrive) / temp_work[flag].run;gWork.push_back(temp_work[flag]);temp_work.erase(temp_work.begin() + flag);//已经运行的作业要删去continue;}for (i = 0; i < n; ++i){if (temp_work[i].arrive <= t2){rate = (t2 - temp_work[i].arrive) / temp_work[i].run + 1;if (max_rate < rate){max_rate = rate;flag = i;}}elsebreak;}t2 += temp_work[flag].run;sum_turn = sum_turn + t2 - temp_work[flag].arrive;//turn = finish - arrivesum_dturn = sum_dturn + (t2 - temp_work[flag].arrive) / temp_work[flag].run;gWork.push_back(temp_work[flag]);temp_work.erase(temp_work.begin() + flag);//已经运行的作业要删去}else{for (i = 0; i < n; ++i){if (temp_work[i].arrive <= t1){rate = (t1 - temp_work[i].arrive) / temp_work[i].run + 1;if (max_rate < rate){max_rate = rate;flag = i;}}elsebreak;}t1 += temp_work[flag].run;sum_turn = sum_turn + t1 - temp_work[flag].arrive;//turn = finish - arrivesum_dturn = sum_dturn + (t1 - temp_work[flag].arrive) / temp_work[flag].run;gWork.push_back(temp_work[flag]);temp_work.erase(temp_work.begin() + flag);//已经运行的作业要删去}}Output();
}

数据:

A 0 7
B 2 10
C 5 20
D 7 30
E 12 40
F 15 8
G 4 8
H 6 20
I 8 10
J 10 12

5.2 实验 2:磁盘调度

5.2.1 实验目的

  1. 对磁盘调度的相关知识作进一步的了解,明确磁盘调度的原理。
  2. 加深理解磁盘调度的主要任务。
  3. 通过编程,掌握磁盘调度的主要算法。

5.2.2 实验内容

  1. 对于如下给定的一组磁盘访问进行调度:
请求服务到达 A B C D E F G H I J K L M N
访问的磁道号 50 100 180 20 90 150 70 80 101 60 120 40 110 30
请求服务到达 A B C D E F G H I J K L M N
  1. 要求分别采用先来先服务、最短寻道优先以及电梯调度算法进行调度。
  2. 要求给出每种算法中磁盘访问的顺序,计算出平均移动道数。
  3. 假定当前读写头在 90 号,向磁道号增加的方向移动。

5.2.3 源代码

#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <stdlib.h>using namespace std;struct Disk
{char name;//请求服务到达序号int number;//访问的磁道号Disk() {}Disk(char n, int num):name(n), number(num){}Disk operator =(const Disk& rhs){this->name = rhs.name;this->number = rhs.number;return *this;}
};const int StartNum = 90;//开始磁道号为90vector<Disk> gDisk;//存储请求服务到达的序列
vector<char> track;//磁道访问顺序
vector<int> MoveDistance;//移动距离
//int FindOrder[MaxNumber];//寻号序列
double TotalDistance;//总共寻到长度
bool direction;//方向,true为向外,false为向内void Readfile();//从txt文件中读取请求服务信息
void Sortnum();//根据磁盘号进行排序,升序
void Fcfs();//先来先服务算法
void Sstf();//最短寻道优先算法
void Scan();//电梯调度算法,也是扫描算法
void Output();//输出结果int main()
{Readfile();Fcfs();Sstf();Scan();return 0;
}void Readfile()
{ifstream ifile;ifile.open("/home/jason/文档/OS/Pro_2/data.txt");if(!ifile){cout << "文档打开失败!" << endl;exit(1);}char name;int num;while(ifile >> name >> num)gDisk.push_back(Disk(name, num));ifile.close();
}
void Sortnum()
{int i(0), j(0);int n = static_cast<int>(gDisk.size());Disk temp;for(i = 0; i < n; ++i){for(j = 0; j < n - i - 1; ++j){if(gDisk[j].number > gDisk[j + 1].number){temp = gDisk[j + 1];gDisk[j + 1] = gDisk[j];gDisk[j] = temp;}}}
}//先来先服务算法
void Fcfs()
{int tempNum = StartNum;//寻道当前所在磁道号track.clear();MoveDistance.clear();int n = static_cast<int>(gDisk.size());//提出的申请数for(int i = 0; i < n; ++i){MoveDistance.push_back(abs(gDisk[i].number - tempNum));track.push_back(gDisk[i].name);tempNum = gDisk[i].number;}cout << "###############先来先服务算法:###############" << endl;Output();
}
//最短寻道优先算法
void Sstf()
{int tempNum = StartNum;//寻道当前所在磁道号track.clear();MoveDistance.clear();vector<Disk> temp_disk;int MinNum = 9999;//最短寻道数int flag = 0;//做标记int n = static_cast<int>(gDisk.size());//提出的申请数for(int i = 0; i < n; ++i){temp_disk.push_back(gDisk[i]);}while(!temp_disk.empty()){MinNum = 9999;int num = 0;//临时存储寻道数flag = 0;n = static_cast<int>(temp_disk.size());for(int i = 0; i < n; ++i){num = abs(temp_disk[i].number - tempNum);if(MinNum > num){MinNum = num;flag = i;}}track.push_back(temp_disk[flag].name);//记录第一个寻道号tempNum = temp_disk[flag].number;MoveDistance.push_back(MinNum);//记录第一个寻道距离temp_disk.erase(temp_disk.begin() + flag);//已访问的删去}cout << "###############最短寻道优先服务算法:###############" << endl;Output();
}//电梯调度算法
void Scan()
{track.clear();MoveDistance.clear();//按磁道号进行排序,升序Sortnum();int n = static_cast<int>(gDisk.size());vector<Disk> temp_disk;for(int i = 0; i < n; ++i)temp_disk.push_back(gDisk[i]);int tempNum = StartNum;int flag(0);for(int i = 0; i < n; ++i){if(temp_disk[i].number < tempNum)continue;else{flag = i;break;}}//最开始是向外寻道for(int i = flag; i < n; ++i){track.push_back(temp_disk[i].name);MoveDistance.push_back(temp_disk[i].number - tempNum);tempNum = temp_disk[i].number;}//然后向里寻道for(int i = flag - 1; i >= 0; --i){track.push_back(temp_disk[i].name);MoveDistance.push_back(tempNum - temp_disk[i].number);tempNum = temp_disk[i].number;}cout << "###############电梯调度算法:###############" << endl;Output();}
//输出结果
void Output()
{int n = static_cast<int>(gDisk.size());//提出的申请数TotalDistance = 0;cout << "寻道序号:" << "   " << "寻道长度:"<<endl;for(int i = 0; i < n; ++i){cout << track[i] << "            "<< MoveDistance[i] << endl;TotalDistance += MoveDistance[i];}cout << "平均寻道长度:" << (static_cast<double>(TotalDistance) / n) << endl;cout << endl;
}

数据:

A 30
B 50
C 100
D 180
E 20
F 90
G 150
H 70
I 80
J 10
K 160
L 120
M 40
N 110

5.3 实验 3:熟悉 linux 文件系统调用

5.3.1 实验目的

  1. 掌握 linux 提供的文件系统调用的使用方法;
  2. 熟悉文件系统的系统调用用户接口;
  3. 了解操作系统文件系统的工作原理和工作方式。

5.3.2 实验内容

使用文件系统调用编写一个文件工具 filetools,使其具有以下功能:

1.创建新文件 2.写文件 3.读文件 4.修改文件权限 5.查看当前文件权限 0.退出

提示用户输入功能号,并根据用户输入的功能选择相应的功能。 文件按可变记录文件组织,具体记录内容自行设计。

5.3.3 预备知识

用户在针对文件进行操作之前时一定要先打开它,这是由于系统需要根据用户提供的参数来查找文件 的目录项,并由目录项找到文件的磁盘 i 结点,再将它调到内存 i 结点,才能建立用户进程与该文件之间的联系。

同样,在文件操作完毕后要关闭文件,以切断用户进程与文件的联系,释放相关资源。

Open 系统调用

int open(const char *path, int flags);
int open(const char *path, int flags,mode_t mode);

一般情况下使用两个参数的格式,只有当打开的文件不存在时才使用 3 个参数的格式。参数:

  • Path 指向所要打开的文件的路径名指针。
  • Flag 标志参数,用来规定打开方式,必须包含以下 3 个之一:
    • O_RDONLY 只读方式
    • O_WRONLY 只写方式
    • O_RDWR 读写方式
  • 利用按位逻辑或“|”对下列标志进行任意组合:
    • O_CREAT 如果文件不存在则创建该文件,若存在则忽略。
    • O_TRUNC 如果文件存在则将文件长度截为 0,属性和所有者不变。
    • C_EXECL 如果文件存在且O_CREAT 被设置则强制 open 调用失败。
    • O_APPEND 每次写入时都从文件尾部开始。
  • Mode 是文件的访问权限,分为文件所有者、文件用户组和其他用户。

Close 系统调用

对于一个进程来说可以同时打开的文件是有限的,为了使文件标识符能够及时释放,系统必须提供关闭文件操作。

Int close(int fd)
  • Fd 为打开文件时系统返回的文件标识符。
  • 系统执行该系统调用时,根据 fd 值在该进程的进程打开文件表中找到 fd 标识,根据指针找到系统打开 文件表,再找到内存i 结点表中相应的 i 结点,对其i_count 进行减 1 操作, 然后释放系统打开文件表中的表项和进程打开文件表的表项。
  • 结果:调用成功返回 0。

5.3.4 源代码

#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>//flag标志参数
#include <sys/stat.h>//文件权限标志位
#include <sys/types.h>#define MAX 10000
int fd;//打开文件时系统返回的文件标识符
char *FileName;//要创建的文件名void Menu();//显示主界面菜单
void CreateFile();//创建新文件
void WriteFile();//写文件
void ReadFile();//读文件
void ModifyPermission();//修改文件权限
void ShowPermission();//查看文件权限int main()
{int select = 0;printf("########欢迎使用文件工具FileTools#######\n");while(1){Menu();scanf("%d", &select);switch (select) {case 0:close(fd);return 0;case 1:CreateFile();break;case 2:WriteFile();break;case 3:ReadFile();break;case 4:ModifyPermission();break;case 5:ShowPermission();break;default:printf("输入有误!请重新输入:\n");}}return 0;
}void Menu()
{printf("########################################\n");printf("########1.创建新文件####################\n");printf("########2.写文件########################\n");printf("########3.读文件########################\n");printf("########4.修改文件权限##################\n");printf("########5.查看文件权限##################\n");printf("########0.安全退出######################\n");printf("请选择:\n");
}//创建新文件
void CreateFile()
{char name[32];printf("请输入要创建的文件名:\n");scanf("%s", name);FileName = name;//O_RDWR:读写方式//O_TRUNC:如果文件存在则将文件长度截为0,属性和所有者不变//O_CREAT:如果文件不存在则创建该文件,若存在则忽略fd = open(FileName, O_RDWR|O_TRUNC|O_CREAT, 0750);if(fd < 0)perror("Create");else{printf("文件创建成功!\n");printf("fd =%d\n", fd);//打印文件的fdclose(fd);//关闭文件}
}//写文件
void WriteFile()
{char name[32];printf("请输入要写入信息的文件名:\n");scanf("%s", name);FileName = name;char buffer[MAX];//存取写入的信息fd = open(FileName, O_WRONLY|O_APPEND);if(fd < 0){perror("Write");return;}printf("请输入要写入的信息:\n");int num = read(0,buffer, MAX);//读取输入信息,0表示标从键盘标准输入write(fd, buffer, num);//将读入的信息写入文件printf("文件写入成功!\n");close(fd);//关闭文件
}//读文件
void ReadFile()
{char buffer[MAX];char name[32];printf("请输入要读取的文件名:\n");scanf("%s", name);FileName = name;fd = open(FileName,O_RDONLY);if(fd < 0){perror("Wrong");return;}int num = read(fd, buffer, MAX);printf("\n");write(1, buffer, num);//向显示屏输出,1表示标准输出printf("\n文件读取成功!\n");close(fd);
}//修改文件权限
void ModifyPermission()
{char name[32];printf("请输入要修改权限的文件名:\n");scanf("%s", name);FileName = name;fd = open(FileName, O_RDONLY);if(fd < 0){perror("Modify");return;}printf("0.所有者用户读写执行\n");printf("1.所有者用户只可读\n");printf("2.所有者用户只可写\n");printf("3.所有者用户只可执行\n");printf("4.用户组读写执行\n");printf("5.用户组只可读\n");printf("6.用户组只可写\n");printf("7.用户组只可执行\n");printf("请选择0-7:");int select;scanf("%d", &select);switch (select){case 0:chmod(FileName, S_IRWXU);break;//文件所有者读写执行权限case 1:chmod(FileName, S_IRUSR);break;//文件所有者读权限case 2:chmod(FileName, S_IWUSR);break;//文件所有者写权限case 3:chmod(FileName, S_IXUSR);break;//文件所有者执行权限case 4:chmod(FileName, S_IRWXG);break;//文件所属组读写执行权限case 5:chmod(FileName, S_IRGRP);break;//文件所属组读权限case 6:chmod(FileName, S_IWGRP);break;//文件所属组写权限case 7:chmod(FileName, S_IXGRP);break;//文件所属执行权限default:printf("错误选择!\n");}close(fd);
}//查看文件权限
void ShowPermission()
{//stat();获取文件信息char name[32];printf("请输入要修改权限的文件名:\n");scanf("%s", name);FileName = name;char *path = "/bin/ls";char *argv[4] = {"ls", "-l", FileName, NULL};execv(path, argv);
}

5.4 实验 4:进程管理

5.4.1 实验目的

  1. 理解进程的概念,明确进程和程序的区别。
  2. 理解并发执行的实质。
  3. 掌握进程的同步、撤销等进程控制方法。

5.4.2 实验内容

  • 父进程使用系统调用 pipe() 建立一个管道,然后使用系统调用 fork() 创建两个子进程:子进程1和子进程2。

  • 子进程1每隔1秒通过管道向子进程2发送数据:I send message x times.(x 初值为1,以后发送一 次后做加一操作)子进程 2 从管道读出信息,并显示在屏幕上。

  • 父进程用系统调用 signal() 来捕捉来自键盘的中断信号(即按Ctrl+C 键);当捕捉到中断信号后,父进程用系统调用 kill() 向两个子进程发出信号,子进程捕捉到信号后分别输出如下信息后终止: Child Process 1 is killed by Parent! Child Process 2 is killed by Parent!

  • 父进程等待两个子进程终止后,释放管道并输出如下的信息后终止 Parent Process is Killed!

5.4.3 源代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>#include <sys/types.h>
#include <sys/wait.h>pid_t child1, child2;//两个子进程
int fd[2];
void SignalHandler1(int iSignNo);//信号处理
void SignalHandler2(int iSignNo);int main()
{int Count = 1;char buffer[40];char info[40];pid_t getpid();printf("Process Parent PID:%d\n", getpid());//创建无名管道,只能在父子或兄弟进程间通信//fd[0]只能用于读,fd[1]只能用于写if(pipe(fd) < 0){printf("管道创建失败!\n");return -1;}//设置软中断信号SIGINT,终端输入Ctrl+C,进程终止signal(SIGINT, SignalHandler1);//创建子进程1,2child1 = fork();if(child1 == 0) //子进程1{printf("Child Process 1 PID:%d\n", getpid());//设置忽略信号,如果不设置,在子进程运行过程直接Ctrl+C,会造成进程终止,//产生僵尸进程,因此需要在子进程中屏蔽,等子进程被父进程kill之后,再在//父进程中Ctrl+C使进程完全结束,就不会产生僵尸进程了signal(SIGINT, SIG_IGN);//设置信号SIGUSR1signal(SIGUSR1, SignalHandler2);while(1){close(fd[0]);sprintf(info, "I send message %d times", Count);//管道长度受到限制,管道写满时写入操作将被阻塞,直到管道中的数据被读取write(fd[1], info, 30);//发送数据至管道数据++Count;//计数器+1sleep(1);//睡眠1s}}else if(child1 > 0)//返回父进程{child2 = fork(); //父进程创建子进程2if(child2 == 0) //子进程2{printf("Child Process 2 PID:%d\n", getpid());//设置忽略信号signal(SIGINT, SIG_IGN);//设置信号SIGUSR1signal(SIGUSR2, SignalHandler2);while(1){close(fd[1]);//当数据被读取后,数据将自动被管道清除//接受管道数据read(fd[0], buffer, 40);//显示管道数据printf("%s\n", buffer);}}else //返回父进程{//等待子进程1,2退出waitpid(child1, NULL, 0);//printf("Child Process 1 is over!\n");waitpid(child2, NULL, 0);//printf("Child Process 2 is over!\n");//关闭管道close(fd[0]);close(fd[1]);printf("Parent Process is Killed!\n");}}return 0;
}void SignalHandler1(int iSignNo)
{printf("\nParent recive signal Ctrl+C\n");if(iSignNo == SIGINT)//传递SIGUSR信号给子进程{//SIGUSR1和SIGUSR2是用户自定义信号,进程终止kill(child1, SIGUSR1);kill(child2, SIGUSR2);}
}void SignalHandler2(int iSignNo)
{close(fd[0]);close(fd[1]);if(child1 == 0 && iSignNo == SIGUSR1){printf("Child Process 1 is killed by Parent!\n");exit(0);}if(child2 == 0 && iSignNo == SIGUSR2){printf("Child Process 2 is killed by Parent!\n");exit(0);}
}

5.5 实验 5:请求分页系统中的置换算法

5.5.1 实验目的

  1. 了解虚拟存储技术的特点;
  2. 掌握请求分页系统的页面置换算法。

5.5.2 实验内容

1、通过如下方法产生一指令序列,共 320 条指令。

A. 在[0,319]的指令地址之间随机选取一起点 M;
B. 顺序执行一条指令,即执行地址为 M+1 的指令;
C. 在前地址[0,M+1]中随机选取一条指令并执行,该指令的地址为 M1;
D. 顺序执行一条指令,其地址为 M1+1;
E. 在后地址[M1+2,319]中随机选取一条指令并执行,该指令的地址为 M2;
F. 顺序执行一条指令,其地址为 M2+1;
G. 重复A—F,直到执行 320 次指令。

2、指令序列变换成页地址流,设 :

(1)页面大小为1K;
(2) 用户内存容量为 4 页到 32 页,步长为 1;
(3)用户虚存容量为 32K。在用户虚存中,按每页存放10 条指令排列虚存地址,即 320 条指令在虚存中的存放方式为: 第0条—第9条指令为第0页(对应虚存地址为[0,9]);第10条—第19条指令为第1页(对应虚存地址为[10,19]) ; …………………… 第310条—第319条指令为第31页(对应虚存地址为[310,319]) ;

按以上方式,用户指令可组成 32 页。

3、计算并输出下述各种算法在不同内存容量下的命中率。

A. 先进先出(FIFO)页面置换算法
B. 最近最久未使用(LRU)页面置换算法–最近最少使用算法
C. 最佳(Optimal)页面置换算法

5.5.3 源代码

#include<iostream>
#include<ctime>
#include<cstdlib>using namespace std;int N = 3;//内存
int Process[320];//页面队列
int Memory[32];//块数
int OPTQueue[320];//OPT算法的队列
int FIFOQueue[320];//FIFO算法队列
int LRUQueue[320];//LRU算法队列
int ttime[320];//设置的一个时间标志,FIFO算法时判断哪个是最先进来的
int flag[320];//设置一个标志,LUR算法判断哪个是最近最久未使用的
int ProcessNum;//页面数
int id[320];//320个进程序列
int address[320];//zhilingzidian
int Size = 0;
int Randf(int l, int r) { return (rand() % (r - l + 1) + l); }void CreateProcess()
{srand(static_cast<unsigned>(time(NULL)));Size = 0;for (int i = 0;i < 64;++i){int m = Randf(0, 319);id[Size++] = m + 1;m = Randf(0, m + 1);id[Size++] = m;id[Size++] = m + 1;m = Randf(m + 2, 319);id[Size++] = m;id[Size++] = m + 1;}cout << "指令序列:" << endl;for (int i = 0;i < Size;++i)cout << id[i] << " ";cout << endl;
}//OPT算法找到最长未使用的
int longest(int start)
{int i;int count[320];for (int i = 0;i < 320;++i)count[i] = 0;for (int j = 0;j < N;++j){for (i = start + 1;i < ProcessNum;i++){if (Memory[j] != OPTQueue[i])count[j]++;if (Memory[j] == OPTQueue[i])break;}}int ti = -1, mmax = -1;for (int i = 0;i < N;++i){if (mmax < Memory[i]){mmax = Memory[i];ti = i;}}return ti;
}
//OPT    算法
void OPT()
{int i, j, k;int num = N;for (i = 0;i < ProcessNum;i++){OPTQueue[i] = Process[i];}for (i = 0;i < N;i++){Memory[i] = OPTQueue[i];}for (i = N;i < ProcessNum; ++i){for (j = 0;j < N;j++){if (Memory[j] == OPTQueue[i])break;}if (j == N){k = longest(i);Memory[k] = OPTQueue[i];num++;}}cout << "命中次数:" << ProcessNum - num << endl;float str;str = (float)(ProcessNum - num)  / ProcessNum;cout << "命中率=" << str * 100 << "%" << endl;
}
//FIFO算法找到最早进来的那个
int MaxTime()
{int ti = -1, mmin = 100000;for (int i = 0;i<N;++i){if (mmin > ttime[i]){mmin = ttime[i];ti = i;}}return ti;
}
//FIFO算法
void FIFO()
{int i, j, k;int num = N;for (i = 0;i<ProcessNum;i++){FIFOQueue[i] = Process[i];}for (i = 0;i<N;i++){Memory[i] = FIFOQueue[i];ttime[i] = i;}for (i = N;i<ProcessNum;i++){for (j = 0;j<N;j++){if (Memory[j] == FIFOQueue[i])break;}if (j == N){k = MaxTime();ttime[k] = i;Memory[k] = FIFOQueue[i];num++;}}cout << "命中次数:" << ProcessNum - num << endl;float str;str = (float)(ProcessNum - num)  / ProcessNum;cout << "命中率=" << str * 100 << "%" << endl;
}
//LRU算法找到最近最久未使用的
int MinFlag()
{int ti = -1, mmin = 100000;for (int i = 0;i < N;++i){if (mmin > flag[i]){mmin = flag[i];ti = i;}}return ti;
}
//LRU算法
void LRU()
{int i, j, k;int num = N;for (i = 0;i<ProcessNum;i++){LRUQueue[i] = Process[i];}for (i = 0;i<N;i++){Memory[i] = LRUQueue[i];flag[i] = i;}for (i = N;i<ProcessNum;i++){for (j = 0;j<N;j++){if (Memory[j] == LRUQueue[i]){flag[j] = i;break;}}if (j == N){k = MinFlag();flag[k] = i;Memory[k] = LRUQueue[i];num++;}}cout << "命中次数:" << ProcessNum - num << endl;float str;str = (float)(ProcessNum - num)  / ProcessNum;cout << "命中率=" << str * 100 << "%" << endl;
}
int main()
{int i;while (N != 0) {cout << "-------------------页面置换算法-------------------------" << endl;cout << "进程数:320" << endl;ProcessNum = 320;CreateProcess();//生成320个指令序列cout << "指令序列生成完毕" << endl << endl;for (i = 0;i < ProcessNum; ++i)Process[i] = id[i] / 10;N = 4;while (N != 1 && N != 0) {cout << "请输入内存容量:[4-32]\n1 for 重新生成指令序列\n0 for 退出程序" << endl;cin >> N;if (N == 0 || N == 1)break;cout << "OPT最佳置换算法" << endl;OPT();cout << endl;cout << "FIFO先进先出页面置换算法" << endl;FIFO();cout << endl;cout << "LRU最近最久未使用置换算法" << endl;LRU();cout << endl;}}return 0;
}

5.6 实验 6:进程通信

5.6.1 实验目的

  1. 理解管道机制、消息缓冲队列、共享存储区机制进行进程间的通信;
  2. 理解通信机制。

5.6.2 实验内容

编写一主程序可以由用户选择如下三种进程通信方式:

  1. 使用管道来实现父子进程之间的进程通信:子进程向父进程发送自己的进程标识符,以及字符串 is sending a message to parent。父进程则通过管道读出子进程发来的消息,将消息显示在屏幕上,然后终止。

  2. 使用消息缓冲队列来实现 client 进程和 server 进程之间的通信:server 进程先建立一个关键字为 SVKEY(如75)的消息队列,然后等待接收类型为REQ (例如 1)的消息;在收到请求消息后,它便显示字符串 serving for client 和接收到的 client 进程的进程标识数,表示正在为 client 进程服务;然后再向 client 进程发送应答消息, 该消息的类型是 client 进程的进程标识数,而正文则是 server 进程自己的标识 ID。client 进程则向消息队列发送类型为 REQ 的消息(消息的正文为自己的进程标识 ID) 以取得 sever 进程的服务,并等待 server 进程发来的应答;然后显示字符串 receive reply from 和接收到的 server 进程的标识 ID。

  3. 使用共享存储区来实现两个进程之间的进程通信:进程 A 创建一个长度为 512 字节的共享内存,并显示写入该共享内存的数据;进程 B 将共 享内存附加到自己的地址空间,并向共享内存中写入数据。

5.6.3 源代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>struct msgform
{long mtype;char mtext[250];
}msg;int msgqid, pid, *pint;
void Menu();
void UsePipe();//使用管道实现父子进程之间的进程通信
void MessageDeque();//使用消息缓冲队列实现C/S进程之间的通信
void Client();
void Server();
void ShareMemory();//使用共享存储区来实现两个进程之间的进程通信
void A();
void B();
int main()
{printf("######欢迎使用“进程通信系统”######\n");while (1) {Menu();int select = 0;scanf("%d", &select);switch (select) {case 0:return 0;case 1:UsePipe();break;case 2:MessageDeque();break;case 3:ShareMemory();break;default:printf("您输入的选择无效,请重新输入!\n");break;}}return 0;
}void Menu()
{printf("##################################\n");printf("1.管道实现父子进程通信\n");printf("2.消息队列C/S进程通信\n");printf("3.共享存储区的进程通信\n");printf("0.安全退出\n");printf("请选择通信方式:\n");}void UsePipe()
{int fd[2];//fd[0]用于读,fd[1]用于写pid_t child;pid_t parent = getpid();printf("Process Parent PID:%d\n", parent);if(pipe(fd) < 0){printf("管道创建失败!\n");return;}child = fork();if(child == 0)//进入子进程{char info[40];close(fd[0]);sprintf(info, "PID:%d is sending a message to parent", getpid());write(fd[1], info, 40);sleep(1);//休眠1sexit(0);}else //返回主进程{close(fd[1]);char buffer[40];read(fd[0], buffer, 40);printf("%s\n", buffer);close(fd[0]);close(fd[1]);waitpid(child, NULL, 0);printf("Process child is over!\n");}
}void MessageDeque()
{int i = 0;while((i = fork()) == -1);//创建进程1if(!i)Server();while((i = fork()) == -1);//创建进程2if(!i)Client();wait(0);wait(0);
}
void Client()
{msgqid = msgget(75, 0400);//打开75消息队列pid = getpid();pint = (int *)msg.mtext;*pint = pid;msg.mtype = 1;//消息类型为1msgsnd(msgqid, &msg, sizeof(int), 0);//发送消息msgrcv(msgqid, &msg, 250, pid, 0);//接收消息printf("(client):reveice reply from pid=%d\n", *pint);exit(0);
}
void Server()
{msgqid = msgget(75, 0400|IPC_CREAT);//创建75消息队列msgrcv(msgqid, &msg, 250, 1, 0);//接收消息//把正文的内容传给pint,并强制转换类型pint = (int *)msg.mtext;pid = *pint;//获得client进程标识数printf("(server):serving for client pid=%d\n", pid);msg.mtype = pid;//消息类型为client*pint = getpid();msgsnd(msgqid, &msg, sizeof(int), 0);//发送消息exit(0);
}void ShareMemory()
{//需要包含头文件<sys/types.h>,<sys/ipc.h>,<sys/shm.h>//shmget函数创建或打开一个新区,返回一个共享存储区ID//int shmget(key_t key, int size, int shmflg)//key:共享存储区的名字,关键字,int型//size:共享存储区的大小(以字节计)//shmflg:用户设置的标志,如IPC_CREAT//IPC_CREAT 表示若系统中尚无指名的共享存储区,//则由核心建立一个共享存储区;如系统中已有共享存储区,便忽略IPC_CREAT//成功返回共享内存的标识符;不成功返回-1,errno 储存错误原因。pid_t a = 0;while ((a = fork()) == -1);if(!a)A();while ((a = fork()) == -1);if(!a)B();wait(0);wait(0);
}
void A()
{int shmid = shmget(100, 512, 0777|IPC_CREAT);//创建共享存储区char *addr = shmat(shmid, 0, 0);//获取首地址printf("get:%s\n", addr);if(shmdt(addr) == 0)printf("A断开链接成功!\n");exit(0);
}
void B()
{int shmid = shmget(100, 512, 0777|IPC_CREAT);//打开共享存储区char *message[] = {"B writes something!"};char *addr = shmat(shmid, 0, 0);//获得共享存储区首地址memset(addr, '\0', 512);//addr内容初始化strncpy(addr, message[0], 512);//向内存中写信息if(shmdt(addr) == 0)printf("B断开链接成功!\n");exit(0);
}

6. 课程设计报告及源代码

https://download.csdn.net/download/diligent_lee/85015283

Linux 操作系统课程设计相关推荐

  1. linux课程设计死锁避免,linux操作系统课程设计—车辆死锁.doc

    linux操作系统课程设计-车辆死锁.doc 键入文字"操作系统原理"课程设计BX090709吴沛儒操作系统原理课程设计报告姓名吴沛儒班级BX0907学号9指导老师胡静二〇一一年十 ...

  2. 检索上Linux操作系统课程的教师名,Linux操作系统课程设计.docx

    课 程 设 计 报 告 课程名称 Linux操作系统课程设计 指导教师 起止日期 2016-03-21 至 2016-06-13 学 院 信息与通信工程学院 专 业 电子信息工程 学生姓名 班级/学号 ...

  3. Linux并发程序课程设计报告,网络操作系统课程设计--进程机制与并发程序设计-linux下生产者与消费者的问题实现.doc...

    网 络 操 作 系 统 课 程 设 计 网络操作系统课程设计 设计内容:进程机制与并发程序设计inux下生产者与消费者的问题实现进程机制与并发程序设计inux下生产者与消费者的问题实现 (1)掌握基本 ...

  4. linux课程设计题目主存空间的分配与回收,可变分区分配与回收,哈尔滨理工大学操作系统课程设计报告.doc-资源下载在线文库www.lddoc.cn...

    可变分区分配与回收,哈尔滨理工大学 操作系统课程设计报告.doc 哈 尔 滨 理 工 大 学 课 程 设 计 ( 操 作 系 统 ) 题 目 可变分区分配与回收 (首次适应算法) 班 级 计算机科学与 ...

  5. 嵌入式linux开发课程设计,嵌入式Linux开发课程设计指导书

    嵌入式Linux开发课程设计指导书 课程编码: 适应专业:计算机专业.电子信息工程专业 学时:3周(计算机专业),2周(电子信息工程专业) 学分: 3(计算机专业),2(电子信息工程专业)时间安排:分 ...

  6. 华科计算机课程设计,华中科大操作系统课程设计报告(附源码).doc

    华中科技大学计算机学院 操作系统课程设计报告 班级: 学号: 姓名:彭博 时间:2010年3月 设计内容一:熟悉和理解Linux编程环境 编写一个C程序,实现文件拷贝功能. 2)编写一个C程序,使用下 ...

  7. python操作系统课程设计_操作系统课程设计.pdf

    计算机科学与通信工程学院 操作系统课程设计报告 题目:linux系统下实现PV 操作 班级: 软件工程1401 姓名: 吴帅帅 学号: 3140608020 指导老师: 牛德姣 2016 年12 月2 ...

  8. GeekOS操作系统课程设计 project1

    GeekOS操作系统课程设计 project1 项目设计1 一.项目设计目的 二.项目设计要求 三.步骤 1.修改project1/src/geekos/elf.c文件 1.1 在函数Parse_EL ...

  9. 华中科技大学计算机课程设计,华中科技大学计算机学院操作系统课程设计资料报告材料[1].doc...

    <华中科技大学计算机学院操作系统课程设计资料报告材料[1].doc>由会员分享,提供在线免费全文阅读可下载,此文档格式为doc,更多相关<华中科技大学计算机学院操作系统课程设计资料报 ...

  10. linux系统编程课程改革,项目驱动的Linux操作系统课程教学改革

    摘 要 <Linux操作系统>是一门应用性很强的课程,在技师学院已被列为计算机网络技术专业的教学计划.在传统的教学模式中,教师往往按照教材编排的顺序,把知识介绍给学生,而不是把知识的应用方 ...

最新文章

  1. OpenStack技术峰会PPT集萃
  2. Linux系统密码忘记修改方法
  3. 错误日志的实时抓取保证代码质量
  4. SAP S/4 Hana On-premise Edition 1511做了哪些简化
  5. php 计算字符串相邻最大重复数_php查找字符串出现次数的方法
  6. 从迁移到Java 7的小技巧
  7. 面试官 | 说一下数据库如何分库分表?
  8. 揭开源码的神秘面纱,让源码从此无处藏身
  9. MDM之Goodness分析报告
  10. 【caffe】基于CNN的年龄和性别检测
  11. linq判断集合中相同元素个数_使用Linq获取集合的最后N个元素?
  12. 关于虚拟机IP更改问题教给大家一个必杀技
  13. 还在为满意的渐变色发愁吗?10+个网站帮你解决烦恼
  14. 数据库异常用户sa登录失败_Sa登录失败
  15. 绿巨人(Hulk - Pure CSS)
  16. 手把手教你编写网页图形验证码识别工具
  17. TypeScript ... 解释三个点的含义
  18. 【优秀易用的无损音乐播放器】Amarra Luxe for Mac 4.3
  19. Python爬虫入门教程07:腾讯视频弹幕爬取
  20. Java正则表达式校验密码规则

热门文章

  1. AIML框架标签详解
  2. Tomcat8安装、配置与启动
  3. 【笔记】人工智能 一种现代方法 人工智能 一种现代方法 第6章 用搜索树对问题求解
  4. 第十四届恩智浦智能汽车大赛车队规划概要
  5. 基于Matpower的电力系统潮流计算设计原理
  6. 小白版----使用vm安装win10
  7. matlab电子类元件库仿真元件,matlab电力系统仿真元件.doc
  8. Linux 常用命令 tar 打包文件夹
  9. uni-app开发环境配置及混合开发流程
  10. sai笔记5-详细上色教程(适合有耐心的观众)