开源操作系统课程设计
开源操作系统课程设计
实验报告
GCC —— Matrix |
SHELL Footscript |
Ncurse —— menu |
Kernel FloppyLinux |
Driver Node & test |
Process fork & pipe |
Pthread PV operate |
Pthread Philosophy |
System Call |
SHELL simulation |
Memory simulation |
Aggregate |
|
|
|
|
|
|
|
|
|
|
|
|
评语
|
- 界面以及结构说明(程序界面菜单以及子菜单的截图和功能说明)
1、GCC Matrix |
编译执行打印螺旋矩阵 |
2、SHELL Footscript |
编写脚本,实现添加和删除用户功能 |
3、Kernel FloppyLinux |
制作FloppyLinux |
4、Driver Node & test |
执行驱动,打印螺旋矩阵 |
5、Process fork & pipe |
实现进程的fork()和进程的pipe() |
6、Pthread PV operate |
用进程实现警察和小偷 |
7、Pthread Philosophy |
用进程实现哲学家问题 |
8、System Call |
系统调用 |
9、SHELL simulation |
模拟实现shell的命令 |
10、Memory simulation |
用首次适应算法实现内存管理 |
- 各个模块说明
1、GCC —— Matrix
(1)实验原理
Vim是从 vi 发展出来的一个文本编辑器。代码补完、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。基本上 vi/vim 共分为三种模式,分别是命令模式(Command mode),输入模式(Insert mode)和底线命令模式(Last line mode)。
vi编辑器是所有Unix及Linux系统下标准的编辑器,他就相当于windows系统中的记事本一样,它的强大不逊色于任何最新的文本编辑器。他是我们使用Linux系统不能缺少的工具。由于对Unix及Linux系统的任何版本,vi编辑器是完全相同的,学会它后,您将在Linux的世界里畅行无阻。vim 具有程序编辑的能力,可以以字体颜色辨别语法的正确性,方便程序设计;因为程序简单,编辑速度相当快速。vim可以当作vi的升级版本,他可以用多种颜色的方式来显示一些特殊的信息。vim会依据文件扩展名或者是文件内的开头信息, 判断该文件的内容而自动的执行该程序的语法判断式,再以颜色来显示程序代码与一般信息。vim里面加入了很多额外的功能,例如支持正则表达式的搜索、多文件编辑、块复制等等。 这对于我们在Linux上进行一些配置文件的修改工作时是很棒的功能。
本次实验在小红帽里写一个简单的C文件,编译运行,打印螺旋矩阵。通过本次实验,熟悉Linux中的命令,学会在终端中通过vi编译器中,编写简单的程序。
(2)实验关键代码
// 输出螺旋矩阵
void Matrix()
{
const int size = 10; // 矩阵大小
int matrix[size][size] = {0};
int row = 0;
int col = 0;
int start = 1; // 起始值
int temp = size;
for (int count = 0; count < size / 2; count++) // size阶的矩阵可以画size/2个圈
{
for (; col < temp - 1; col++) // a排赋值
matrix[row][col] = start++;
for (; row < temp - 1; row++) // b排赋值
matrix[row][col] = start++;
for (col = temp - 1; col > count; col--) // c排赋值
matrix[row][col] = start++;
for (row = temp - 1; row > count; row--) // d排赋值
matrix[row][col] = start++;
// 进入下一圈
temp--;
row++;
start -= 1; // 这里-1是因为在换圈的时候会多加1
}
if (0 != size % 2) // 如果size为奇数则最后会有一个数遍历不到,这里补上
matrix[row][col+1] = start + 1;
// 输出数组
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
printf(" %d",matrix[i][j]);
}
printf("\n");
}
}
(3)程序流程图(手写)
(4)实验结果及总结
通过本次实验,加深了我对Linux操作系统的认识,加深了我对Linux的指令的认识。通过这次实验,我熟悉了 linux 下 c 语言程序的编写,掌握了 vi 的一些常用操作,学会了使用 gcc 命令和 makefile 文件两种方法编译程序。同时也使我熟悉了 linux 里常用命令的使用,还有,学会了挂载 U盘的方法,可以很方便的往 linux 里传送文件。
2、SHELL Footscript
(1)实验原理
Shell脚本(英语:Shell script)是一种电脑程序与文本文件,内容由一连串的shell命令组成,经由Unix Shell直译其内容后运作。被当成是一种脚本语言来设计,其运作方式与直译语言相当,由Unix shell扮演命令行解释器的角色,在读取shell script之后,依序运行其中的shell命令,之后输出结果。利用Shell script可以进行系统管理,文件操作等。
在Linux中默认安装就带了shell解释器。
(2)实验关键代码
#!/bin/sh
i=1
while [ $i -le 4 ]
do
GROUPNAME=class${i}
groupadd $GROUPNAME
i=$(($i+1))
done
i=0
k=0
while [ $i -lt 120 ]
do
if [ $(($i%30)) -eq 0 ]
then
k=$(($k+1))
fi
j=$((($i)%30))
j=$(($j+1))
if [ $j -le 9 ]
then
USERNAME=class${k}stu0${j}
else
USERNAME=class${k}stu${j}#
fi
GROUPNAME=class${k}
useradd $USERNAME
chown -R $USERNAME /home/$USERNAME
chgrp -R $GROUPNAME /home/$USERNAME
i=$(($i+1))
Done
(3)程序流程图(手写)
(4)实验结果及总结
通过本次实验,学会了脚本程序的编写,学会了利用脚本实现简单的功能。这是课程设计的第二次实验,通过这几次实验,体会到了乐趣。
3、Kernel FloppyLinux
(1)实验原理
在虚拟机中虚拟一张1.44M的软盘,就可以制作自己的Linux操作系统了,通过本实验可以对Linux的开机启动过程,根文件系统的制作,内核的编译有更深的理解。创建一个启动盘首先必须创建根文件系统,由于软盘容量有限,因此常采用压缩的根文件系统。
一个启动盘实际上是一个完整系统的缩影,它能够执行一个完整系统的大部分功能。引导系统就是在操作系统内核运行之前运行的一段小程序,能够初始化硬件设备、建立内存空间的映射图,并且为最终调用操作系统内核准备好正确的环境;而内核是一个操作系统的核心,负责管理系统的进程、存储、设备和文件等功能,决定着系统的性能和稳定性.
(2)实验关键代码
timeout 0
default 10
title wangjian’FloppyLinux
root (fd0)
kernel /boot/bzImage
initrd /initrd.img.gz
(3)程序流程图(手写)
(4)实验结果及总结
通过本次实验,我了解了 linux 系统的启动过程,进一步熟悉了 linux 内核编译过程。学会
了 floppylinux 的制作方法,做成之后非常有成就感。我认为本实验并不难,考验的是细心。实
验步骤很多,每个步骤出现错误,都有可能导致实验失败。所以要力求每个步骤准确无误,特别
是建立启动配置文件的时候,要仔细核对每一个单词,特别注意空格。前面几遍没有成功没有成功,原因就出在这里。总之,面对一个步骤复杂的事情,要细心。
4、Driver Node & test
(1)实验原理
驱动程序,英文名为“Device Driver”,全称为“设备驱动程序”,它是一种特殊的程序。首先其作用是将硬件本身的功能告诉操作系统,接下来的主要功能就是完成硬件设备电子信号与操作系统及软件的高级编程语言之间的互相翻译。
Linux内核使用驱动时候,需要先初始化,包括建立设备文件,分配内存地址空间等,退出的时候要释放资源,删除设备文件,释放内存地址空间等。所以在linux驱动中需要提供两个函数来分别处理驱动初始化和退出的工作,这两个函数分别用module_init和module_exit宏来指定,linux驱动一般都需要指定这两个函数,所以linux驱动有一个C文件,文件中包含处理驱动初始化和退出的函数,以及指定这两个函数的module_init和module_exit宏.
在Linux操作系统下有三类主要的设备文件类型,一是字符设备,二是块设备,三是网络设备。字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O操作。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。
本次实验主要是针对字符设备来进行操作。主要操作步骤如下:
- 修改Makefile文件内容。修改内核源码路径:/usr/src/linux-2.4,修改gcc前缀,设置为空。
- 执行make操作,生成evan.o、test_demo等。
- insmod evan.o。可以通过lsmod查看是否成功。
- 建立驱动结点。执行mknod /dev/evan c 99 0。
- 最后执行。/test_demo。
(2)实验关键代码
static void do_write()//do_wiite()函数,在这里面生成螺旋。
{
int i;
int start=65;int row=0;int col=0;
int m=M;int n=N;int cnt;int flag=1;
if(M>=N)
{cnt=N;}
else
{cnt=M+1;}
for(i=0;i<cnt/2;i++)
{
for(;col<n-1;col++)
{drv_buf[row*N+col]=start;start++;}
if(row>=m-1)
{flag=0;}
for(;row<m-1;row++)
{drv_buf[row*N+col]=start;start++;}
for(col=n-1;col>i;col--)
{
drv_buf[row*N+col]=start;
start++;
if(flag==0)
{break;}
}
for(row=m-1;row>i;row--)
{drv_buf[row*N+col]=start;start++;}
m--;n--;row++;start--;
}
start++;
if(N%2!=0)
{
int z=M-2*row;for(i=0;i<z;i++)
{
drv_buf[row*N+col+1]=start;
start++;row++;
}
}
}
static ssize_t evan_write(struct file *filp, char *buffer, size_t count)// evan_write()函数
{
if (count>MAX_BUF_LEN) count=MAX_BUF_LEN;
copy_from_user(drv_buf,buffer,count);
WRI_LENGTH=count;
M=buffer[0];
N=buffer[1];
printk("user write data to drivers!\n");
do_write();
return count;
}
(3)程序流程图(手写)
(4)实验结果及总结
通过本次实验,加深了我对驱动程序的认识,Linux系统将每一个驱动都映射成一个文件。这些文件称为设备文件或驱动文件,都存在/dev目录中。这样,在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作,从而大大方便了对设备的处理。
通过在应用程序中生成数组,输入行数与列数,并将其传到驱动程序中,进而生成螺旋矩阵函数,使我对驱动程序有了初步的认识。
5、Process fork & pipe
(1)实验原理
每个进程各自有不同的用户地址空间,任 何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲 区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
管道是一种最基本的IPC机制,由pipe函数创建。调用pipe函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端一个写端,然后通过filedes参数传出给用户程序两个文件描述符。所以管道在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,调用失败返回-1。
由fork创建的新进程被称为子进程(child process)。该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新进程(子进程)的进程 id。将子进程id返回给父进程的理由是:因为一个进程的子进程可以多于一个,没有一个函数使一个进程可以获得其所有子进程的进程id。对子进程来说,之所以fork返回0给它,是因为它随时可以调用getpid()来获取自己的pid;也可以调用getppid()来获取父进程的id。
(2)实验关键代码
(3)程序流程图(手写)
(4)实验结果及总结
通过本次实验,我对操作系统的进程有了更深入的了解,为接下来的进程实验打下基础。这次实验老师给了大部分的代码,实现起来相对简单。同时,加深了我对操作系统理论课上学到的知识的理解。
6、Pthread PV operate
(1)实验原理
警察与小偷一个十分经典的多线程并发协作的模式,在深刻理解生产者-消费者问题的基础上,警察与小偷问题能够让我们对并发编程的理解加深。所谓生产者-消费者问题,实际上主要是包含了两类进程,一种是生产者进程用于生产数据,另一种是消费者进程用于消费数据,为了解耦生产者和消费者的关系,通常会采用共享的数据区域,就像是一个仓库,生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为;而消费者只需要从共享数据区中去获取数据,就不再需要关心生产者的行为。而警察与小偷问题,同样包含两类进程,警察进程和小偷进程,与生产者消费者问题不同的是,小偷可以在警察前面,警察也可以在小偷前面,但是彼此之间的距离不能超过3米。
(2)实验关键代码
void put(struct prodcons * b, int data)
{
pthread_mutex_lock(&b->lock);
while (b->writepos - b->readpos >=2) {
pthread_cond_wait(&b->notfull, &b->lock);
}
b->buffer[b->writepos] = data;
b->writepos++;
initP(b->writepos,b->readpos);
pthread_cond_signal(&b->notempty);
pthread_mutex_unlock(&b->lock);
}
int get(struct prodcons * b)
{
int data,i;
pthread_mutex_lock(&b->lock);
while (b->writepos - b->readpos <= -4) {
pthread_cond_wait(&b->notempty, &b->lock);
}
data = b->buffer[b->readpos];
b->readpos++;
initP(b->writepos,b->readpos);
pthread_cond_signal(&b->notfull);
pthread_mutex_unlock(&b->lock);
return data;
}
(3)程序流程图(手写)
(4)实验结果及总结
这个程序我结合着老师给生产者消费者程序框架,重新整理思路,认识到警察与小偷问题同样包含两类进程,警察进程和小偷进程,与生产者消费者问题不同的是,小偷可以在警察前面,警察也可以在小偷前面,但是彼此之间的距离不能超过3米。而生产者与消费者问题,强制要求了生产者必须在消费者的前面,并且二者的距离不能超过缓冲池的长度。
思路明确后,编程就变得简单了。同时实验要求使用ncurses,将文字式的输出编程生动的动画,令人印象深刻。
7、Pthread Philosop hy
(1)实验原理
哲学家进餐问题描述:一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是99根面条。哲学家们倾注毕生精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿的时候,才试图拿起左、 右两根筷子(一根一根地拿起)。如果筷子已在他人手上,则需等待。饥饿的哲学家只有同时拿到了两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。
实验思路是在界面上画一张圆桌,五个哲学家围桌而坐,每两个哲学家中间有一个筷子,圆桌中间有一个数字代表剩余面条的数目。
(2)实验关键代码
void init(int i,int noddle)
{
clear();char a,b;
if(noddle>=10)
{a=noddle/10+'0';b=noddle%10+'0';mvaddch(4,9,a);mvaddch(4,10,b);}
else
{a=noddle+'0';mvaddch(4,9,a);}
mvaddch(0,10,'B');mvaddch(4,0,'A');mvaddch(4,20,'C');mvaddch(8,15,'D');mvaddch(8,5,'E');
mvaddstr(2,3,"--------------");mvaddstr(6,3,"--------------");
mvaddch(2,3,'|');mvaddch(3,3,'|');mvaddch(4,3,'|');mvaddch(5,3,'|');
mvaddch(3,17,'|');mvaddch(4,17,'|');mvaddch(5,17,'|');mvaddch(6,17,'|');
if(i==1)
{mvaddch(5,2,'-');mvaddch(3,2,'-');mvaddch(4,15,'-');mvaddch(5,15,'|');mvaddch(5,5,'|');}
else if(i==2)
{mvaddch(4,4,'-');mvaddch(1,12,'|');mvaddch(1,8,'|');mvaddch(5,15,'|');mvaddch(5,5,'|');}
else if(i==3)
{mvaddch(4,4,'-');mvaddch(3,10,'|');mvaddch(5,18,'-');mvaddch(3,18,'-');mvaddch(5,5,'|');}
else if(i==4)
{mvaddch(4,4,'-');mvaddch(3,10,'|');mvaddch(4,15,'-');mvaddch(7,17,'|');mvaddch(7,13,'|');}
else
{mvaddch(7,7,'|');mvaddch(3,10,'|');mvaddch(4,15,'-');mvaddch(5,15,'|');mvaddch(7,3,'|');}
refresh();
}
void initfh(int noddle)
{
clear();char a,b;
if(noddle>=10)
{a=noddle/10+'0';b=noddle%10+'0';mvaddch(4,9,a);mvaddch(4,10,b);}
else
{a=noddle+'0';mvaddch(4,9,a);}
mvaddch(0,10,'B');mvaddch(4,0,'A');mvaddch(4,20,'C');mvaddch(8,15,'D');mvaddch(8,5,'E');
mvaddstr(2,3,"--------------");mvaddstr(6,3,"--------------");
mvaddch(2,3,'|');mvaddch(3,3,'|');mvaddch(4,3,'|');mvaddch(5,3,'|');
mvaddch(3,17,'|');mvaddch(4,17,'|');mvaddch(5,17,'|');mvaddch(6,17,'|');
mvaddch(4,4,'-');mvaddch(3,10,'|');mvaddch(4,15,'-');mvaddch(5,15,'|');mvaddch(5,5,'|');
refresh();
}
(3)程序流程图(手写)
(4)实验结果及总结
第一次用ncurses画这么负责的图,使我对ncurses的功能有了更深刻的认识,简单的ncurses却能实现如此强大的功能。这次实验花费了很多时间花费了好多时间用来画图,使我对ncurses的使用有了更深刻的认识。
在完成这个实验的过程中,我遇到了许多的困难,但是好在通过同学的帮助,我慢慢的一一解决了。总的来说,哲学家算法是一个经典的课题,此次的实践的带给我的收获绝不止实现一个实验这么简单。
8、System Call
(1)实验原理
系统调用是内核提供的、功能十分强大的一系列函数。它们在内核中实现,然后通过一定的方式呈现给用户,是用户程序与内核交互的一个接口。如果没有系统调用,则不可能编写出十分强大的用户程序,因为失去了内核的支持。由此可见系统调用的地位举足轻重。
应用程序执行系统调用之后,将进行模式转换,从用户态切换到内核态,之后在内核空间调用内核函数。执行完毕后又从内核态切换回用户态,并在原来的应用程序断点继续执行下去。
本次实验通过在添加打印螺旋矩阵的系统调用,进而证明这个进程进入过内核态。
(2)实验关键代码
asmlinkage int sys_print_info(int m,int n)
{
printk(KERN_EMERG "my id is 1609030225\n");
printk(KERN_EMERG "my name is wangjian\n");
char a[100][100];
int x, y;
int total = 0;
int cnt = 0;
x = 0, y = 0;
a[x][y] = 0;
while(total < m*n){
while(y+1<n&&!a[x][y+1]){
a[x][++y] = ++cnt;
++total;
}
while(x+1<m&&!a[x+1][y]){
a[++x][y] = ++cnt;
++total;
}
while(y-1>=0&&!a[x][y-1]){
a[x][--y] = ++cnt;
++total;
}
while(x-1>=0&&!a[x-1][y]){
a[--x][y] = ++cnt;
++total;
}
}
for(x = 0;x < m;x++){
for(y = 0;y < n;y++){
printk(KERN_EMERG " %d",a[x][y]);
}
printk(KERN_EMERG "\n");
}
return 0;
}
(3)程序流程图(手写)
(4)实验结果及总结
本次实验通过添加一个简单的系统调用,打印出自己的学号和姓名,并且实现了输入行数和列数打印螺旋矩阵。
需要注意本次系统调用与前一次的驱动打印螺旋矩阵的不同,虽然两个实验都需要进行终端和系统调用,但是本次系统调用实验需要重新编译内核,而驱动实验只是建立驱动节点而已。
系统调用是一层用户进入内核的接口,通过实验加深了操作系统理论课上学习到知识,系统调用与普通的函数调用非常相似,区别仅仅在于,系统调用由操作系统核心提供,运行于核心态;而普通的函数调用由函数库或用户自己提供,运行于用户态。通过实验,我认识到了内核的重要性,在以后的学习中,我会更加努力。
9、SHELL simulation
(1)实验原理
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
(2)实验关键代码
#!/bin/sh
who(){
echo "wangjian 1609030225"
}
bye(){
echo "before exit"
exit
echo "after exit"
}
pwd(){
workdir=$(cd $(dirname $0) :pwd)
echo ”$workdir"
}
down( ){
shutdown -r now
}
wc -1 < infile
exec 0< infile
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done
who >> outfile
pwd >> outfile
bye >> outfile
(3)程序流程图(手写)
(4)实验结果及总结
通过本次shell脚本编程实验,学会了了利用shell实现部分系统的内部命令(bye、down、who、pwd等)和外部命令,并且实现了输入输出重定向功能。
本次实验的感悟到shell命令很神奇,通过一系列命令就可以搞定文件的操作,在这些命令之后再加一些字母,便可以做一些更加详细的操作。
10、Memory simulation
(1)实验原理
通过首次适应算法,然后在ncurses图形界面下显示手动显示内存申请和内存释放功能。
首次适应算法从空闲分区表的第一个表目起查找该表,把最先能够满足要求的空闲区分配给作业,这种方法目的在于减少查找时间。为适应这种算法,空闲分区表(空闲区链)中的空闲分区要按地址由低到高进行排序。该算法优先使用低址部分空闲区,在低址空间造成许多小的空闲区,在高地址空间保留大的空闲区。
思路是利用数据结构中的二叉树,内存申请时,便插入左右孩子,左孩子为作业,右孩子为空闲区。申请内存时便在界面上打印“-”,表示该段内存被占用,同时在中间打印出内存大小。释放内存时,在界面上打印“ ”,便是该段内存被释放。
(2)实验关键代码
void Insert_PreOrder(pBiTree p,int length,int homework)//内存申请函数
{
initscr();
crmode();
noecho();
if(p != NULL)
{
if((p->state==0)&&(length<p->length)&&(!p->lchild)&&(!p->rchild)&&temp==0)
{
pBiTree x1 =new BiTNode;//进行插入,动态申请两个空间 x1,x2
pBiTree x2 =new BiTNode;
x1->homework=homework;//x1为作业
x2->homework=NULL;//x2为剩余的空闲区
x1->address=p->address;//把原空闲区的首地址给作业的首地址
x1->state=1;//作业的状态改为1
x1->length=length;//作业的长度为传入的长度
int i;
for(i=x1->address; i<x1->address+x1->length; i++)
{
mvaddch(13,i,'-');
}
char c,b;
int j=x1->length;
if(i>=10)
{
c=j/10+'0';
b=j%10+'0';
mvaddch(13,x1->address+x1->length/2,c);
mvaddch(13,1+x1->address+x1->length/2,b);
}
else
{
c=j+'0';
mvaddch(13,x1->address+x1->length/2,c);
}
mvaddch(12,i,'|');mvaddch(13,i,'|');mvaddch(14,i,'|');
x2->address=x1->address+length;//新空闲亲地址与x1长度之和
x2->length=p->length-x1->length;
p->lchild=x1;
p->rchild=x2;
x2->state=0;
x1->lchild=NULL;
x1->rchild=NULL;
x2->rchild=NULL;
x2->lchild=NULL;
temp=1;
}
else
{
Insert_PreOrder(p->lchild,length,homework); //遍历左子树
Insert_PreOrder(p->rchild,length,homework); //遍历右子树
}
}
refresh();
endwin();
}
void Delect_PreOrder(pBiTree p,int homework) //内存释放函数,遍历修改,将状态修改为0。
{
initscr();
crmode();
noecho();
if(p != NULL)
{
if(p->homework==homework)//当查询到作业名相同的作业。进行修改
{
p->homework=NULL;//将作业名修改为空
p->state=0;
int i;
for(i=p->address; i<p->address+p->length; i++)
{
mvaddch(13,i,' ');
}
}
Delect_PreOrder(p->lchild,homework); //遍历左子树
Delect_PreOrder(p->rchild,homework); //遍历右子树
}
refresh();
endwin();
}
(3)程序流程图(手写)
(4)实验结果及总结
通过这次实验,学会了通过首次适应算法,来进行申请内存和释放内存。实验中在使用ncurses打印图形界面时,遇到了bug(执行程序没有任何反应),通过上网查资料,发现需要在每次进行操作(内存申请和内存释放)时,都需要对界面进行刷新,所以我在内存申请函数和内存释放函数中添加
ncurses初始化函数并进行刷新,问题得到了解决。
- 课程总结以及建议
通过本学期的开源操作系统课程设计,加深了理论课操作系统学到的知识。通过这十一次的实验,从最开始的Linux基础的指令,到后面的进程管理、存储器管理等等。其中的系统调用和驱动对我影响很大,最开始我的疑问是为什么系统调用实验需要重新编内核,而驱动实验不需要重新编译内核,只需要通过insmod添加节点。
非常感谢老师这一个学期的辛苦指导。实验过程中遇到了许多问题,通过老师和同学们的帮忙最终都一一克服了。