第一篇:操作系统课设任务
一、操作系统课程设计要求:
1.每个学生从以下给定题目中选做至少一项,也可以针对操作系统课程实验已完成的题目进行扩充完善; 2.设计周周末向各班学习委员交源程序、设计报告的电子版和打印版; 3.编程工具不限
二、操作系统课程设计题目:(在以下题目中任选一个题目进行设计)
1.进程同步问题(信号量机制)(任选其一)1)生产者消费者问题 2)哲学家进餐问题 3)读者-写者问题 4)吃水果问题 5)售票员售票问题
2.进程(作业)调度算法(任选其中三种算法)1)先来先服务算法 2)短进程(作业)优先算法 3)优先数优先算法 4)最高响应比优先算法 5)时间片轮转调度算法
3.实时调度算法 1)最早截止时间优先 2)最低松弛度优选 4.银行家算法(死锁避免)
5.动态分区分配算法(连续存储器管理方式)
首次适应算法、循环首次适应算法、最佳适应算法、最差适应算法 6.页面置换算法
最佳置换算法OPT、先进先出算法FIFO、最近最久未使用算法LRU 7.磁盘调度算法
先来先服务算法、最短寻道时间优先算法、扫描算法(电梯调度算法)8.缓冲池管理
三、操作系统课程设计任务书
封皮
指导教师评语
第一部分:需求分析(课题描述、课题目的、理论依据)第二部分:概要设计(设计方法、技术、运行环境等)第三部分:详细设计(流程图、程序主要代码)
第四部分:运行结果及分析(运行结果(可以截图)、结果详细分析)第五部分:总结和心得 参考文献: 附录:程序源代码
注:程序详细代码附在电子版中即可,打印版可不打印。
课程设计时间:2018年1月1日——2018年1月5日
第二篇:操作系统课设
操作系统课程设计
一实验目的
在多道程序或多任务系统中,系统中同时处于就绪态的进程有若干个,也就是说能运行的进程数远远大于处理机个数。为了使系统中的各进程能有条不紊地进行,必须选择某种调度策略,以选择一进程占用处理机。要求学生设计一个模拟单处理机调度的算法,以加深对处理机调度的概念理解。
通过自己变成来实现页面调度算法,进一步理解页面调度算法 的概念及含义,提高对页面调度算法的认识,同时提高自己的动手实践能力。加深我们对主存与辅助存储器统一管理、逻辑地址与物理地址转换、部分装入和部分替换问题的理解,同时,有利于我们对虚拟存储技术的理解。
为了了解系统的资源分配情况,假定系统的任何一种资源在 任一时刻只能被一个进程使用。任何进程已经占用的资源只能由进程自己释放,而不能由其他进程抢占。当进程申请的资源不能满足时,必须等待。因此,只要资源分配算法能保证进程的资源请求,且不出现循环等待,则系统不会出现死锁。
编写模拟系统进行资源调度的程序,一个是随机算法,即只 要系统剩余资源能满足进程的当前请求,就立即将资源分配给进程,以观察死锁产生情况;一个是采用银行家算法,有效地避免死锁的产生。
模拟进程的资源分配算法,了解死锁的产生和避免的办法。通过设计一个磁盘调度模拟系统,深入理解磁盘的工作原理,从而使磁盘调度更加形象化,容易使人理解,使磁盘调度的特点更简单明了,能使使用者加深对磁盘调度算法的理解。具体实现为,运用一门高级编程语言编写程序模拟磁盘调度的过程,采用先来先服务算法和电梯算法,模拟并输出存取臂的移动顺序,并计算存取臂移动的磁道总数。能够处理以下的情形:
(1)可根据需要输入当前磁头的位置,磁头移动方向;(2)能够输入柱面数,磁道访问序列等参数,并能够显示调度结果(磁盘访问请求的磁道号以及磁头移动的总磁道数)。
二、实验内容
利用C++实验以下算法: 处理机管理中:
(1)先来先服务算法(FCFS)
实验题目:
<1>假设系统中有3~5个进程,每个进程由一个进程控制块(PCB)来标识。
<2>设置一个队首指针head,用来指出最先进入系统的进程,各就绪进程通过链接指针连在一起。
<3>处理机调度时总是选择队首指针指向的进程投入运行。由于本实验是模拟实验,所以对被选中进程并不实际启动运行,而只是执行。估计运行时间减1,用这个操作来模拟进程的一次运行,而且省去进程的现场保护和现场恢复工作。
<4>在所设计的程序中应有显示或打印语句,能显示或打印正运行的进程名字、已运行时间、还剩时间、就绪对列中进程名字等。所有进程运行完成时,给出各进程的周转时间和平均周转时间.数据结构设计如下:
struct PCB
//定义进程控制块
{
char ID[3];
//进程号
char name[10];
//进程名
char state;
//运行状态
int arrivetime;//到达时间
int starttime;//进程开始时间
int finishtime;//进程结束时间
int servicetime;
//运行时间
float turnaroundtime;//周转时间
float weightedturnaroundtime;//带权周转时间
struct PCB *next;//指向下个进程
};
(2)时间片轮算法
实验题目:
<1>假设系统中有3~5个进程,每个进程由一个进程控制块(PCB)来代表。
<2>按照进程到达的先后顺序排成一个循环队列,设一个队首指针指向第一个到达的进程的首址。另外再设一个当前运行进程指针,指向当前正运行的进程。
<3>执行处理机调度时,首先选择队首的第一个进程运行。<4>由于本实验是模拟实验,所以对被选中进程并不实际启动运行,而只是执行:
估计运行时间减1 用这个操作来模拟进程的一次运行。
<5>进程运行一次后,以后的调度则将当前指针依次下移一个位置,指向下一个进程,即调整当前运行指针指向该进程的链接指针所指进程,以指示应运行进程,同时
还应判断该进程的剩余运行时间是否为0.若不为0,则等待下一轮的运行,若该进程的剩余运行时间为0,则将该进程的状态置为完成状态“C”,并退出循环队列。<6>若就绪队列不空,则重复上述的步骤(4)和(5)直到所有进程都运行完为止。
<7>在所设计的调度程序中,应包含显示或打印语句吧,已便显示或打印每次选中进程的名称及运行一次后队列的变化情况。数据结构设计如下:
typedef struct pcb
//进程控制块定义
{
char pname[N];
//进程名
int runtime;
//运行时间
int arrivetime;
char state;
struct pcb*next;
}PCB;PCB head_input;
PCB head_run;
PCB *pcb_input;
void inputprocess();
函数
int readydata();
int runprocess();
进程的函数
int readyprocess();
static char R='r',C='c';
量
unsigned long current;
//到达时间
//进程状态 //链接指针
//就绪队列头指针 //运行队列头指针
//判断是否有就绪进程的 //运行进程的函数
//检查就绪队列并准备运行
//声明一个文件指针
//记录系统当前时间的变
//建立进程的函数
(3)优先级调度算法
实验题目:
<1>假设系统中有3~5个进程,每个进程由一个进程控制块(PCB)来代表。进程的优先数、要求运行时间和估计运行
时间由用户程序任意设计,且优先数越低,优先级越高。调度时,总是选择优先级最高的进程运行。
<2>为了调度方便,设计一个指针指向就绪队列的第一个进程。另外再设一个当前运行进程指针,指向当前正运行的进程。
<3>处理机调度时,总是选择已经到达队列的优先级最高的进程运行。为了采用 动态优先级调度,进程每运行一次,其优先级就减1。由于本实验是模拟实验,所以对被选中进程并不实际启动运行,而只是执行:
优先数加1和估计运行时间减1 用这个操作来模拟进程的一次运行。
<4>进程运行一次后,若剩余的运行时间不为0,且其优先级低于就绪队列的其他进程的优先级,则选择一个高优先级进程抢占CPU;若剩余运行时间为0,则把它的状态改为完成状态“C”,并撤出就绪队列。
<5>若就绪队列不空,则重复上述的步骤(3)和(4)直到所有进程都运行完为止。
<6>在所设计的程序中应有显示或打印语句,以显示或打印每次被选中进程的进程名字、运行一次后进程的变化以及就绪队列中的各进程排队情况等。数据结构设计如下:
struct pcb {
/* 定义进程控制块PCB */
char name[10];
//进程名
char state;
//进程状态
int super;
//优先级数
int ntime;
//需要运行时间
int rtime;
//已运行时间 页面替换算法中:
(1)先进先出页面替换算法(FIFO)(2)最近最少使用页面替换算法(LRU)(3)最少使用频率页面替换算法(LFU)
数据结构设计如下:
struct PageFrame
//页框结构 {
int id;
//页框号
int pageId;
//驻留的页号
int visitedCount;//驻留页计数器,访问加1 int unvisitedCount;//最近访问,访问清零,未访问加1 bool replace;//将被淘汰为true int stayTime;
//驻留时间计数 int nextsite;};银行家算法 实验题目
<1>
为了观察死锁产生和避免的情况,要求设计3~4个并发进程,共享系统的10个同类补课抢占的资源。各进程是动态进行资源的申请和释放。
<2>
用随机算法和银行家算法分别设计一个资源分配程序,运行这两个程序,观察系统运行情况,并对系统运行的每一步情况进行显示。
程序中使用的数据结构及主要符号说明
初始化这组进程的最大资源请求和依次申请的资源序列,把进程已占用和需求的资源情况记录在进程控制块中,假定进程控制块的格式如下图所示;
进程状态有:就绪、等待和完成。当系统不能满足进程的资源请求时,进程处于等待态。
“资源需求总量”表示进程运行过程中对资源的最大需求量。显然每个进程的资源需求总量不应超过系统拥有的资源总量。“已占资源量”表示进程目前已经得到但还未归还的资源量。因此,进程在以后还需要的剩余资源量等于资源需要总量减去已占资源量。“当前申请量”指进程都拿过去按运行时需要申请的资源量。银行家算法分配资源的原则是:
(1)当某个进程提出资源请求时,假定先分配给它,之后调用系统安全性检查算法,进行系统安全性检查,若系统安全,须分配变为真分配。否则作废假分配,让进程等待。(2)系统安全性检查算法。驱动调度算法中:
作为操作系统的辅助存储器,用来存放文件的磁盘是一类高速大容量旋转型存储设备,在繁重的I/O负载下,同时会有若干传输请求来到并等待处理,系统必须采用一种调度策略,按照最佳次序执行要求访问的诸多请求,减少为若干I/O请求服务所需消耗的总时间。
磁盘驱动调度对磁盘的效率有重要影响。磁盘驱动调度算法的好坏直接影响辅助存储器的效率,从而影响计算机系统的整体效率。(1)电梯调度算法(2)最短查找时间优先算法(3)先来先服务算法
三、实验心得
通过本次课程设计,我认识到要将操作系统这门计算机专业课学好不易——不仅仅是要把书上的基本知识学好,而且还要不断进行实践,将所学与实践操作结合起来才能更好地巩固所学,才能提高自己实践能力。在以后的学习中一方面我要不断的巩固自己所学的理论知识,一方面还要多参加实际操作工作以便提高自己的实际操作能力。
第三篇:操作系统课设
课 程 设 计 报 告
课程名称: 计算机操作系统
专业班级:
学 号: 姓 名: 指导教师: 报告日期:
计算机科学与技术学院
华 中 科 技 大 学 课 程 设 计 报 告
目 录 2 3 实验目的..............................................................................................2 实验环境..............................................................................................2 实验内容..............................................................................................2 3.1 3.2 3.3 3.4 3.5 4 实验一...............................................................................................2 实验二...............................................................................................2 实验三...............................................................................................2 实验四(选做)................................................................................3 实验五(选做)................................................................................3
设计与实现...........................................................................................3 4.1 4.2 4.3 4.4 实验一...............................................................................................3 实验二.............................................................................................10 实验三.............................................................................................14 实验四.............................................................................................20 心得体会............................................................................................43
I
华 中 科 技 大 学 课 程 设 计 报 告 ·掌握Linux操作系统的使用方法; ·了解Linux系统内核代码结构; ·掌握实例操作系统的实现方法;
实验目的 实验环境
本次课程设计采用的操作系统环境是windows8、Ubuntu双系统,Ubuntu系统版本号为14.04,内核版本号为linux 3.13.0;采用的编程环境为CodeBlocks IDE和QtCreator。3.1 实验一
实验内容
掌握Linux操作系统的使用方法,包括键盘命令、系统调用;掌握在Linux下的编程环境。
(1)编写一个C程序,其内容为实现文件拷贝的功能。
(2)编写一个C程序,其内容为分窗口同时显示三个并发进程的运行结果。要求用到Linux下的图形库(GTK/Qt)。
3.2 实验二
掌握系统调用的实现过程,通过编译内核方法,增加一个新的系统调用,另编写一个应用程序,调用新增加的系统调用。实现的功能是:文件拷贝。
3.3 实验三
掌握增加设备驱动程序的方法。通过模块方法,增加一个新的设备驱动程序,其功能可以简单。(实现字符设备的驱动)
华 中 科 技 大 学 课 程 设 计 报 告
3.4 实验四(选做)
了解和掌握/proc文件系统的特点和使用方法(1)了解/proc文件的特点和使用方法;
(2)监控系统状态,显示系统中若干部件使用状态;(3)用图形界面实现系统监控状态;
3.5 实验五(选做)
设计并实现一个模拟的文件系统。
多用户的多级目录的文件系统设计。多用户、多级目录、login(用户登录)、系统初始化(建文件卷,提供登录模块)、文件的创建、文件的打开、文件的读写、文件关闭、删除文件、创建目录(建立子目录)、改变当前目录、列出文件目录、退出。4.1 实验一
4.1.1 实验要求
设计与实现
掌握Linux操作系统的使用方法,包括键盘命令、系统调用;掌握在Linux下的编程环境。4.1.2 具体实现
本实验内容是用CodeBlocks IDE实现的,该软件整合了函数库和编译器,因此使用起来非常方便。
(1)编写一个C程序,其内容为实现文件拷贝的功能。
在windows操作系统上实现的文件拷贝功能一般使用fopen、fread、fwrite三个来自标准C函数库的函数执行对文件的打开、读、写操作,而本次实验要求使用Linux系统的系统调用open、read、write实现上述三个操作。
用到的主要头文件如下:
华 中 科 技 大 学 课 程 设 计 报 告
stdio.h——标准输入输出头文件 string.h——字符串处理相关头文件
unistd.h——Linux系统调用头文件,比如read、write fcntl.h——包含open系统调用
errno.h——包含一些调试错误时用到的变量 具体实现思路:
打开两个文件(分别是源文件和目标文件,可以是任意字符流形式存储的文件,包括文本文件、照片等),调用read函数读取源文件的内容,将read的返回值作为while循环的判断条件,当返回值大于0(即还未读取完毕源文件中的内容)时,调用write执行向目标文件写的操作,否则跳出循环,表示源文件已经被拷贝到目标文件,然后调用close关闭源文件和目标文件。
代码编写完成后,在CodeBlocks上编译运行即可。程序运行之前,桌面上只有“教程.docx”,运行之后,桌面上新建了“教程副本.docx”,并且“教程.docx”中的内容被复制到了“教程副本.docx”,程序运行结果如下所示:
详细代码见4.1.3。
(2)编写一个C程序,其内容为分窗口同时显示三个并发进程的运行结果。要求用到Linux下的图形库(GTK/Qt)。
华 中 科 技 大 学 课 程 设 计 报 告
本次实验使用的图形库是跨平台的开发工具Qt。首先下载Qt的安装包并安装。Qt安装完之后,先新建一个Qt控制台应用MAIN作为主进程,用于调用三个并发的子进程。在主进程的main函数中,使用fork创建三个子进程,若进程创建成功(即fork函数返回值等于0),则使用execv函数进入对应的子进程(get、copy、put)。主进程程序编写完成后,再新建三个Qt Widgets Application,分别作为三个子进程get、copy、put(所实现的功能并不是拷贝)。由于三个子进程窗口显示的内容形式一模一样,所以以子进程get为例。get进程的窗口显示了一下四个内容:当前时间、子进程名称、子进程的pid和父进程MAIN的pid。用Qt的对象QDateTime获取系统当前时间,然后将时间转换成一个字符串写在一个QLabel类的实例中,然后将该实例添加至窗口;直接把当前进程名称写在一个标签上然后添加至窗口;使用getpid和getppid函数分别获取当前进程号和父进程号,然后调用sprintf把进程号转换成字符串类型之后写在标签上并添加至窗口即可。
主进程和三个子进程的程序全部编写完后,直接在Qt上编译运行。程序运行结果如下所示:
华 中 科 技 大 学 课 程 设 计 报 告
详细代码见4.1.3。
华 中 科 技 大 学 课 程 设 计 报 告
4.1.3 源代码(1)文件拷贝源代码
#include
#define SIZE 10
///每次读取的字符数目
char * srcFile=“/home/ilbear/桌面/教程.docx”;char *goalFile=“/home/ilbear/桌面/教程副本.docx”;
int main(int argc, const char *argv[]){
int src, goal;
int read_len;
char buff[SIZE];
src=open(srcFile,O_RDONLY);
if(src<0)
{
printf(“Fail to open %sn.”,srcFile);
exit(1);
}
goal=open(goalFile,O_WRONLY|O_CREAT,0666);
if(goal<0)
{
printf(“Fail to open %sn.”,goalFile);
exit(1);
}
while((read_len=read(src,buff,SIZE))>0)
{
write(goal,buff,read_len);
}
close(src);
close(goal);
return 0;}(2)三个并发进程
#主进程MAIN #include
华 中 科 技 大 学 课 程 设 计 报 告
{
QCoreApplication a(argc, argv);
pid_t p1,p2,p3;
if((p1=fork())==0)
{
execv(“/home/ilbear/桌面/build-get-Desktop_Qt_5_4_1_GCC_64bit-Debug/get”,NULL);
}
else
{
if((p2=fork())==0)
{
execv(“/home/ilbear/桌面/build-copy-Desktop_Qt_5_4_1_GCC_64bit-Debug/copy”,NULL);
}
else
{
if((p3=fork())==0)
{
execv(“/home/ilbear/桌面/build-put-Desktop_Qt_5_4_1_GCC_64bit-Debug/put”,NULL);
}
}
}
waitpid(p1,NULL,0);
waitpid(p2,NULL,0);
waitpid(p3,NULL,0);
return a.exec();}
#子进程get mainwindow.cpp #include “mainwindow.h” #include “ui_mainwindow.h” #include
QMainWindow(parent),ui(new Ui::MainWindow),sharememory1(“share1”){
ui->setupUi(this);
setWindowTitle(“get”);
setWindowFlags(Qt::Dialog);
move(0,0);
resize(500,500);
char str[128],f_id[128];
sprintf(str,“%d”,getpid());
sprintf(f_id,“%d”,getppid());
ui->textBrowser->setText(“get”);
ui->textBrowser_2->setText(str);
ui->textBrowser_3->setText(f_id);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(timerUpDate()));
华 中 科 技 大 学 课 程 设 计 报 告
timer->start(1);} MainWindow::~MainWindow(){
delete ui;} void MainWindow::timerUpDate(){
QDateTime time = QDateTime::currentDateTime();
QString str = time.toString(“yyyy-MM-dd hh:mm:ss dddd”);
ui->labelCurDate->setText(str);}
#子进程copy mainwindow.cpp #include “mainwindow.h” #include “ui_mainwindow.h” #include
QMainWindow(parent),ui(new Ui::MainWindow),sharememory1(“share1”),sharememory2(“share2”){
char str[128],f_id[128];
ui->setupUi(this);
setWindowTitle(“copy”);
setWindowFlags(Qt::Dialog);
move(500,500);
resize(500,500);
sprintf(str,“%d”,getpid());
sprintf(f_id,“%d”,getppid());
ui->textBrowser->setText(“copy”);
ui->textBrowser_2->setText(str);
ui->textBrowser_3->setText(f_id);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(timerUpDate()));
timer->start(1);} MainWindow::~MainWindow(){
delete ui;} void MainWindow::timerUpDate(){
QDateTime time = QDateTime::currentDateTime();
QString str = time.toString(“yyyy-MM-dd hh:mm:ss dddd”);
ui->labelCurDate->setText(str);}
#子进程put mainwindow.cpp #include “mainwindow.h” #include “ui_mainwindow.h”
华 中 科 技 大 学 课 程 设 计 报 告
#include
QMainWindow(parent),ui(new Ui::MainWindow),sharememory2(“share2”){
char str[128],f_id[128];
ui->setupUi(this);
setWindowTitle(“put”);
setWindowFlags(Qt::Dialog);
move(1000,0);
resize(500,500);
sprintf(str,“%d”,getpid());
sprintf(f_id,“%d”,getppid());
ui->textBrowser->setText(“put”);
ui->textBrowser_2->setText(str);
ui->textBrowser_3->setText(f_id);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(timerUpDate()));
timer->start(1);} MainWindow::~MainWindow(){
delete ui;} void MainWindow::timerUpDate(){
QDateTime time = QDateTime::currentDateTime();
QString str = time.toString(“yyyy-MM-dd hh:mm:ss dddd”);
ui->labelCurDate->setText(str);} 4.2 实验二
4.2.1 实验要求
掌握系统调用的实现过程,通过编译内核方法,增加一个新的系统调用,另编写一个应用程序,调用新增加的系统调用。4.2.2 具体实现(1)系统调用的原理
用户进程不能访问内核所占内存空间,也不能调用内核函数。进程调用一个特殊的指令,这个指令会跳到一个事先定义的内核中的一个位置。在Intel CPU中,由中断INT 0x80实现。(与DOS功能调用int0x21很相似)跳转到的内核位置叫做sysem_call。检查系统调用号,这个号码代表进程请求哪种服务。然后,它查看系统
华 中 科 技 大 学 课 程 设 计 报 告
调用表(sys_call_table)找到所调用的内核函数入口地址。接着,就调用函数,等返回后,做一些系统检查,最后返回到进程(如果这个进程时间用尽,就返回到其他进程)。
(2)编写新的系统调用程序
新的系统调用程序实现的功能是:将一个文件中的内容拷贝到另一个文件中。这个系统调用的参数是两个char*型的字符指针SourceFile、GoalFile,分别表示源文件和目标文件的路径名。用户进程中的open、read、write、close函数此时对应内核函数 sys_open、sys_read、sys_write、sys_close函数。循环拷贝的判断条件还是
sys_read的返回值,当其大于0的时候执行循环,否则表示源文件已拷贝到了目标文件。
mm_segment_t类型的变量fs的作用是在读写文件前得到当前fs,避免使用的缓冲区超过了用户空间的地址范围而报错。
详细代码见4.2.3。(3)编译内核 ①下载并解压内核
先到Linux官方网站http://www.xiexiebang.comtl.h> #define BUFFER_SIZE 102400 int main(void){ int dev,i=0;char c;
char source[BUFFER_SIZE];//写入MyDeviceDriver设备的内容
char goal[BUFFER_SIZE];//MyDeviceDriver设备的内容读入到该goal中
printf(“input the string you want to write in your device:n”);while((c=getchar())!='n')
华 中 科 技 大 学 课 程 设 计 报 告
{
source[i++]=c;} printf(“n”);
if((dev=open(“/dev/MyDeviceDriver”,O_RDWR))==-1)//打开MyDeviceDriver设备失败
printf(“FAIL to open MyDeviceDriver!n”);else//成功
printf(“SUCCESS to open MyDeviceDriver!n”);
printf(“source:n%snn”,source);
write(dev,source,sizeof(source));//把source中的内容写入MyDeviceDriver设备
lseek(dev,0,SEEK_SET);//把文件指针定位到文件开始的位置
read(dev,goal,sizeof(source));//把MyDeviceDriver设备中的内容读入到goal中
printf(“goal:n%snn”,goal);
return 0;} 4.4 实验四
实验四有两个选做题目,分别是proc文件监控系统和小型文件系统,本次实验我选择的题目是proc文件监控系统。4.4.1 实验要求
了解/proc文件的特点和使用方法;监控系统状态,显示系统中若干部件使用状态;用图形界面实现系统监控状态。4.4.2 具体实现
(1)/proc文件系统的特点
Linux的PROC文件系统是进程文件系统和内核文件系统的组成的复合体,是将内核数据对象化为文件形式进行存取的一种内存文件系统,是监控内核的一种用户接口。它拥有一些特殊的文件(纯文本),从中可以获取系统状态信息。(2)功能清单
①获取并显示主机名,与之相关的proc文件为/proc/sys/kernel/hostname; ②获取并显示系统启动的时间,与之相关的proc文件为/proc/uptime; ③显示系统到目前为止持续运行的时间,与之相关的proc文件为/proc/uptime; ④显示系统的版本号,与之相关的proc文件为/proc/sys/kernel/ostype和/proc/sys/kernel/osrelease;
⑤ 显示CPU的型号和主频大小,与之相关的proc文件为/proc/cpuinfo;
华 中 科 技 大 学 课 程 设 计 报 告
⑥通过pid或者进程名查询一个进程,并显示该进程的详细信息,提供杀掉该进程的功能,与之相关的proc文件为/proc/(pid)/stat;
⑦显示系统所有进程的一些信息,包括pid、ppid、占用内存大小、优先级等,与之相关的proc文件为/proc/(pid)/stat,/proc/(pid)/statm;
⑧CPU使用率的图形化显示(2分钟内的历史记录曲线),与之相关的proc文件为/proc/stat;
⑨内存和交换分区的使用率的图形化显示(2分钟内的历史曲线),与之有关的proc文件为/proc/meminfo;
⑩在状态栏显示当前时间,未使用到/proc中的文件;
⑪在状态栏显示当前CPU使用率,与之相关的proc文件为/proc/stat; ⑫在状态栏显示当前内存使用情况,与之相关的proc文件为/proc/meminfo; ⑬用新线程运行一个其他程序,未使用到/proc中的文件; ⑭关机功能,未使用到/proc中的文件;(3)功能实现
①获取并显示主机名
用fopen函数打开/proc/sys/kernel/hostname文件,然后以文件指针为输入流,用fgets从其中读出一行字符包含主机名,然后用格式化输出函数sscanf函数输出一个字符串,即主机名。
②获取并显示系统启动的时间
从文件/proc/uptime中获取系统启动到现在的运行时间(单位是s),然后调用time函数获取系统当前时间(单位是s),用当前时间秒数减去运行时间秒数即为系统启动的时间秒数,然后调用localtime函数将系统启动时间秒数转换成tm结构体类型的变量,该变量中的成员包括年份、月份、日期、星期几、时、分、秒等,再调用输出函数输出即可。
③显示系统到目前为止持续运行的时间
用fopen函数打开/proc/uptime文件,然后以文件指针为输入流,用fgets从其中读出一行字符包含系统运行时间,然后用格式化输入函数sscanf从读取出的字符流中输入一个float类型的数到runtime,即系统运行的时间。
④显示系统的版本号
华 中 科 技 大 学 课 程 设 计 报 告
从/proc/sys/kernel/ostype和/proc/sys/kernel/osrelease中读取系统类型(比如linux)和系统内核版本号,处理方法和获取系统运行时间的方法一样。得到系统类型和系统内核版本号之后,调用QString类的方法arg将两个字符串连接起来,再输出显示即可。
⑤显示CPU的型号和主频大小
打开/proc/cpuinfo文件后发现CPU有四个,相同的型号,不同的主频,后来才弄清楚所谓的四个CPU是CPU的四个核心,而“主频”并不是主频,而是当前时刻该核心所使用的CPU核心频率,随时间而变化的。
弄清楚文件中的内容的含义之后,开始处理/proc/cpuinfo,从中读取CPU的型号和频率。处理这个文件没有用到fopen等函数,而是使用了Qt自带的两个类QFile和QTextStream,定义一个QFile类型的变量file,并用路径名“/proc/cpuinfo”初始化该变量,其作用是以只读方式打开文件/proc/cpuinfo,然后以file的地址作为参数初始化QTextStream类型的变量stream,其作用是将/proc/cpuinfo文件中的内容以字符流的形式存入变量stream中,相当于一个文本流。由于CPU的型号是一样的,所以只读取第一个型号名称即可,根据CPU型号名称所在的行,采用while循环读取stream中的内容,每次读取一行,当行数等于CPU型号所在行时,将读取出的一行赋值给一个QString类型的变量,再调用QString的方法mid截取CPU型号名称,file.close()关闭file。CPU四个核心的主频处理方法和CPU型号的处理方法一致,参照上述步骤即可。
⑥通过pid或者进程名查询一个进程,并显示该进程的详细信息,提供杀掉该进程的功能
在获取所有进程信息的时候,获取到的所有信息已经被存储在一个全局结构体数组变量中了,所以查询的时候,先获取输入lineEdit中的文本(QString类型),然后将文本与全局结构体数组变量的每一个数组元素的name成员和pid成员作比较,若相等,说明待查询的进程存在,将该进程的详细信息输出即可。
杀死进程前先要获取将要被杀死进程的名称或者pid,而且该进程必须存在于/proc目录下,即先查询一次待杀死的进程,处理方法如上所述。Linux系统提供了kill、pkill等杀死进程的命令,pkill通过pid杀死进程,kill通过进程名称杀死进程。通过将lineEdit中的内容和kill或pkill组成终端命令,然后调用system函数执行这
华 中 科 技 大 学 课 程 设 计 报 告
些命令即可杀死相应的进程。
⑦显示系统所有进程的一些信息,包括pid、ppid、占用内存大小、优先级等 系统的进程众多,且进程号从1到几万的都有,如果从1开始遍历访问,效率就会很低。所以本次实验我采用的是Linux中对目录进行操作的函数opendir(),readdir()。这两个目录操作函数在上学期的操作系统第三次课程实验中已经学习使用过,所以再次使用没遇到多大的障碍。
实现思路为:声明一个DIR类型的指针dir,用opendir函数打开/proc目录,返回值赋值给dir,然后将dir作为函数readdir的参数,readdir函数返回值复制给dirent结构体指针ptr。ptr指向的结构体包含d_name char数组成员,即文件或者目录名,将d_name数组的0号元素分别和字符„1‟、„9‟比较,若处于这两者之间,则表明该文件或者目录是进程目录,以该目录名为参数调用获取进程详细信息的函数read_proc。在read_proc函数中,使用格式化输出函数sprintf将参数目录名c_pid对应目录下的文件stat的路径输出到char数组filename中,再调用C++的类ifstream,声明一个ifstream类性的变量meminfo,用filename初始化meminfo,然后用析取器(>>)从meminfo中输入数据到结构体数组procInfo的每个元素的成员变量中,析取器(>>)会自动忽略空字符。所需要的进程信息并不是连续存放在stat文件中的,中间包含有其他不需要显示的进程信息,解决方法是定义一个string类型的变量temp,根据stat文件中的信息存放顺序,将所有不需要的进程信息全部输入到temp中。此外还要注意一个问题,进程名称带有括号“()”,所以需要将括号去掉,解决方法是使用string类的方法substr,该函数的参数有两个,一个是想截取的字符串首字符在原字符串中的位置,第二个参数是想截取的字符串末尾字符后面一个字符,在这里就是“)”。处理完毕之后,所需要的关于进程c_pid的详细信息都存储在全局结构体数组procInfo的元素中了。
循环采用上述思路,直到所有进程目录都被处理完毕,所有的进程信息就都存储在了全局结构体数组procInfo中,然后用定时器触发定时更新全局结构体数组procInfo中的内容。
⑧CPU使用率的图形化显示
由于需要画出CPU使用率两分钟内的历史记录曲线,所以需要计算并存储120个连续时刻的CPU利用率。定义一个全局QList变量yList,用于存放CPU使用率。
华 中 科 技 大 学 课 程 设 计 报 告
在CPURate函数中调用add_point函数,add_point的参数是cpuRate。在函数add_point中,首先判断yList的大小,若大于120,则把yList的队首元素删除,保证yList的元素个数恒等于120;若等于0,则将yList前119个元素初始化为0,这样的话,CPU历史记录曲线就会从右边向左边逐渐显示出来;若大于等于1,则在yList末尾插入新的cpuRate,然后调用UpdateCPULine函数画出记录曲线。
得到CPU使用率之后,在函数UpdateCPULine中画图。先在QPixmap类型的变量pix上画曲线,pix相当于一块画布,然后再把pix添加到label标签上。pix的背景色设置为蓝色,然后定义一个QPainter类painter,painter的画图设备就是pix,定义QPen画笔pen,画笔颜色设置为红色,画笔宽度为2个像素,设置完成后,以yList中存储的cpuRate为纵坐标,以yList的元素下标为横坐标,并根据坐标轴单位长度所占实际像素个数稍微调整一下每个点的横纵坐标,然后调用painter的drawLine方法画出这些点并依次连接起来,就得到了2分钟内的CPU使用率历史记录曲线,而且历史记录曲线可以随着时间从右向左更新。
⑨内存和交换分区的使用率的图形化显示
由于需要画出内存使用率两分钟内的历史记录曲线,所以需要计算并存储120个连续时刻的内存利用率。定义一个全局QList变量yList1,用于存放内存使用率。在MemRate函数中调用add_point函数,add_point的参数是memRate。在函数add_point中,首先判断yList1的大小,若大于120,则把yList1的队首元素删除,保证yList1的元素个数恒等于120;若等于0,则将yList1前119个元素初始化为0,这样的话,内存使用率历史记录曲线就会从右边向左边逐渐显示出来;若大于等于1,则在yList1末尾插入新的memRate,然后调用UpdateMemLine函数画出记录曲线。
得到内存使用率之后,在函数UpdateMemLine中画图。先在QPixmap类型的变量pix上画曲线,pix相当于一块画布,然后再把pix添加到label标签上。pix的背景色设置为蓝色,然后定义一个QPainter类painter,painter的画图设备就是pix,定义QPen画笔pen,画笔颜色设置为红色,画笔宽度为2个像素,设置完成后,以yList1中存储的memRate为纵坐标,以yList1的元素下标为横坐标,并根据坐标轴单位长度所占实际像素个数稍微调整一下每个点的横纵坐标,然后调用painter的drawLine方法画出这些点并依次连接起来,就得到了2分钟内的内存使用率历史记
华 中 科 技 大 学 课 程 设 计 报 告
录曲线,而且历史记录曲线可以随着时间从右向左更新。
⑩在状态栏显示当前时间
调用QDateTime的方法currentDateTime获取当前时间time,time是一个QDateTime类型的变量,然后调用QDateTime的方法toString把time转化成格式为yyyy-MM-dd hh:mm:ss dddd的QString字符串,再在主窗口的状态栏显示输出即可。⑪在状态栏显示当前CPU使用率
CPU的使用率是指CPU的使用时间和CPU总时间的比值。因为/proc/stat文件中的所有值都是从系统启动开始累计到当前时刻,所以计算CPU使用率时需要取两个采样点,利用两个点的差值计算CPU使用率,此次实验采样方法是每隔1秒采样一次。CPU使用率的计算公式为cpuRate=100.0-(idle2-idle1)*100.0/(total2-total1)。定义一个全局结构体CPU_USE,具体定义如下:
typedef struct CPU_USE {
char name[16];//cpu
unsigned int user;
unsigned int nice;
unsigned int system;
unsigned int idle;
unsigned int iowait;
unsigned int irq;
unsigned int softirq;}cpu_use;CPU总时间的值等于结构体CPU_USE中7个unsigned int类型的成员值之和。计算之前,调用get_cpu_use_stat函数获取一个CPU状态,sleep一秒后再调用该函数获取第二个CPU状态,然后用上述CPU使用率计算公式计算即可。
⑫在状态栏显示当前内存使用情况
内存使用率是指已使用的内存和总内存的比值。内存使用率的计算公式为:memRate=(total –(free+buffers+cached))*100.0/total。
定义一个全局结构体MEM_USE,具体定义如下:
华 中 科 技 大 学 课 程 设 计 报 告
typedef struct MEM_USE{
unsigned long total;
unsigned long free;
unsigned long buffers;
unsigned long cached;}mem_use;该结构体中的成员的值都来自文件/proc/meminfo,声明一个ifstream类性的变量meminfo,用/proc/meminfo初始化meminfo,然后用析取器(>>)从meminfo中输入数据到结构体mem_use 的成员变量中,析取器(>>)会自动忽略空字符。所需要的内存数据信息并不是连续存放在/proc/meminfo文件中的,中间包含有其他不需要的内存数据信息,解决方法是定义一个string类型的变量str,根据/proc/meminfo文件中的信息存放顺序,将所有不需要的内存数据信息全部输入到str中。得到内存使用的数据信息之后,使用上述内存使用率计算公式计算即可。⑬用新线程运行一个其他程序
在主窗口中添加一个lineEdit控件,获取该控件中输入的程序名称,然后调用QProcess类的start方法运行该程序。⑭关机功能
由于关机功能需要输入密码获取root权限,所以需要想方法在点击关机按钮后输入密码。定义一个QString类型的变量passWord,调用类QInputDialog的方法getText,会弹出一个对话框提示输入密码,该方法的返回值即为密码,将返回值赋值给passWord变量;当对话框的OK按钮被点击时,用QString(“echo %1 | sudo-S shutdown-h now”).arg(passWord)初始化QString类型的变量sudo,再把sudo转换成char*类型,然后调用system函数执行关机命令。(4)界面设计
新建一个Qt Widgets Application工程,用setWindowTitle函数将主窗口的标题改为“proc进程管理器”,设置窗口的初始大小为(650,500),初始位置为显示屏左上角,即坐标原点。
在主窗口底部添加一个状态栏控件,用QStatusBar实现。状态栏中添加三个标签和一个按钮,三个标签分别用于显示当前时间、CPU使用率、内存使用率,这三
华 中 科 技 大 学 课 程 设 计 报 告
个信息的显示函数都与定时器QTimer绑定,随时间自动更新,按钮用于触发关机函数。
在主窗口的窗体中添加tabWidget控件,设置四个tab选项卡tab_
1、tab_
2、tab_
3、tab_4。tab_1选项卡用于显示主机名、系统启动时间、系统运行时间、系统版本号、CPU型号和主频等信息,这些内容全部用QLabel类的标签显示,其中系统运行时间和CPU主频函数是槽函数,都和定时器QTimer绑定,随着时间自动更新。tab_2选项卡用于显示进程详细信息,进程详细信息包括进程名、pid、ppid、内存占用和优先级,这些信息用tableWidget控件显示,tableWidget控件设置为禁止选中、禁止修改,tableWidget的列数是固定的5列,行数动态确定,由获取所有进程详细信息的函数get_pid_info的返回值提供;这样做的好处是,当创建新进程或者杀死进程时,tableWidget不会出现行数不够或者有空行的情况,并且ProcessInfo函数(即控制显示进程信息的函数)与QTimer绑定,随时间定时更新。tab_3选项卡用于提供查询进程、杀死进程、创建新进程的操作面板,查询进程的输入框用lineEdit控件实现,该控件的好处是可以直接调用控件所包含的方法text获取输入框的内容,便于查询进程信息;在lineEdit下方放置的是tableWidget控件,同样,该控件禁止选中、禁止修改,用于显示查询的进程详细信息;tableWidget控件下方是关闭进程的按钮,当点击该按钮时便会触发killProcess函数关闭进程;创建进程的进程名输入框同样也是用lineEdit控件实现,当点击“运行”按钮时便会触发CreateProcess函数。tab_4选项卡用于显示CPU使用率历史记录曲线和内存使用率历史记录曲线。(5)程序运行结果
华 中 科 技 大 学 课 程 设 计 报 告
华 中 科 技 大 学 课 程 设 计 报 告
4.4.3 源代码
#mainwindow.h,包含各种槽函数
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include
Q_OBJECT
华 中 科 技 大 学 课 程 设 计 报 告
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();private:
Ui::MainWindow *ui;private:
QPushButton* shutButton;
QLabel* NowTimeLabel;
QLabel* CPUUseLabel;
QLabel* MemUseLabel;
QTabWidget* tabwidget;
QList
QList
void init_StatusBar();
void HostName();
void BootTime();
void OSType();
void add_point(float cpuRate);
void UpdateCPULine();
void add_point_mem(float memRate);
void UpdateMemLine();private slots:
void NowTime();
void CPURate();
void MemRate();
void run_time();
void CPUInfo();
void ProcessInfo();
void QueryProcess();
void PasswordToShutdown();
void KillProcess();
void CreateProcess();};#endif // MAINWINDOW_H
#sys.h,获取主机名、系统运行时间、系统版本号
#ifndef SYS #define SYS #include
FILE* fp;
char host[8];
char *hostname;
hostname=(char*)malloc(7*sizeof(char));
fp=fopen(“/proc/sys/kernel/hostname”,“r”);
fgets(host,sizeof(host),fp);
sscanf(host,“%s”,hostname);
fclose(fp);
return hostname;} float get_run_time_sec()
华 中 科 技 大 学 课 程 设 计 报 告
{
FILE* fp;
float runTime;
char time[32];
fp=fopen(“/proc/uptime”,“r”);
fgets(time,sizeof(time),fp);
sscanf(time,“%f”,&runTime);
fclose(fp);
return runTime;} QString get_os_type(){
QString os;
char ostype[6],osrelease[8];
char buff1[16],buff2[16];
FILE *fp1,*fp2;
fp1=fopen(“/proc/sys/kernel/ostype”,“r”);
fp2=fopen(“/proc/sys/kernel/osrelease”,“r”);
fgets(buff1,sizeof(buff1),fp1);
fgets(buff2,sizeof(buff2),fp2);
sscanf(buff1,“%s”,ostype);
sscanf(buff2,“%s”,osrelease);
os=QString(“%1 %2”).arg(ostype).arg(osrelease);
fclose(fp1);
fclose(fp2);
return os;} #endif // SYS
#process.h,获取所有进程详细信息
#ifndef PROCESS #define PROCESS #include
string name;
string pid;
string ppid;
string rss;
string priority;}procInfo[40960];void read_proc(PROC_INFO *pidinfo,const char *c_pid){
string temp,pidname;
char filename[18];
sprintf(filename,“/proc/%s/stat”,c_pid);
std::ifstream meminfo(filename);
meminfo>>(pidinfo->pid)>>pidname>>temp>>(pidinfo->ppid)>>temp>>temp;
meminfo>>temp>>temp>>temp>>temp>>temp>>temp;
华 中 科 技 大 学 课 程 设 计 报 告
meminfo>>temp>>temp>>temp>>temp>>temp>>(pidinfo->priority);
meminfo>>temp>>temp>>temp>>temp>>temp>>(pidinfo->rss);
pidinfo->name=pidname.substr(1,pidname.find(')')-1);//remove“()”
meminfo.close();} int get_pid_info(){
DIR *dir;
struct dirent *ptr;
int i=0;
if(!(dir=opendir(“/proc”)))
return 0;
while((ptr=readdir(dir))!=false)
{
if(ptr->d_name[0]>='1' && ptr->d_name[0]<='9')
{
read_proc(&(procInfo[i]),ptr->d_name);
i++;
}
}
closedir(dir);
return i;} #endif // PROCESS
#mem.h,计算内存使用率
#ifndef MEM #define MEM #include
unsigned long total;
unsigned long free;
unsigned long buffers;
unsigned long cached;}mem_use;void get_mem_use_stat(mem_use *memStat){
string str;
unsigned long memtotal,memfree,memavailable,membuffers,memcached;
std::ifstream meminfo(“/proc/meminfo”);
meminfo>>str>>memtotal>>str;
meminfo>>str>>memfree>>str;
meminfo>>str>>memavailable>>str;
meminfo>>str>>membuffers>>str;
meminfo>>str>>memcached>>str;
(*memStat).total=memtotal;
(*memStat).free=memfree;
(*memStat).buffers=membuffers;
(*memStat).cached=memcached;
meminfo.close();
华 中 科 技 大 学 课 程 设 计 报 告
} float clacu_memRate(mem_use *memStat){
float memRate=0.0;
memRate=(float)(((*memStat).totalruntime;
ptm = localtime(&boot_time);
boot=QString(“%1-%2-%3 %4:%5:%6 %7”).arg(ptm->tm_year+1900).arg(ptm->tm_mon+1).arg(ptm->tm_mday).arg(ptm->tm_hour).arg(ptm->tm_min).arg(ptm->tm_sec).arg(week[ptm->tm_wday]);
ui->bootlabel->setText(boot);} void MainWindow::OSType(){
QString os;
os=get_os_type();
ui->ostypelabel->setText(os);} void MainWindow::PasswordToShutdown(){
QString passWord;
QString sudo;
char* command;
bool OK;
QByteArray ba;
passWord=QInputDialog::getText(this,“输入密码”,“输入密码”,QLineEdit::Normal,“",&OK);
if(OK)
{
sudo=QString(”echo %1 | sudo-S shutdown-h now“).arg(passWord);
ba=sudo.toLatin1();
command=ba.data();
华 中 科 技 大 学 课 程 设 计 报 告
system(command);
} } void MainWindow::CPUInfo(){
QString processor;
QString Hz0,Hz1,Hz2,Hz3;
processor=get_processor();
ui->processorlabel0->setText(QString(”0: %1“).arg(processor));
ui->processorlabel1->setText(QString(”1: %1“).arg(processor));
ui->processorlabel2->setText(QString(”2: %1“).arg(processor));
ui->processorlabel3->setText(QString(”3: %1“).arg(processor));
Hz0=get_Hz0();
Hz0=QString(”%1%2“).arg(Hz0).arg(”MHz“);
ui->Hzlabel0->setText(Hz0);
Hz1=get_Hz1();
Hz1=QString(”%1%2“).arg(Hz1).arg(”MHz“);
ui->Hzlabel1->setText(Hz1);
Hz2=get_Hz2();
Hz2=QString(”%1%2“).arg(Hz2).arg(”MHz“);
ui->Hzlabel2->setText(Hz2);
Hz3=get_Hz3();
Hz3=QString(”%1%2“).arg(Hz3).arg(”MHz“);
ui->Hzlabel3->setText(Hz3);} void MainWindow::ProcessInfo(){
int pidNum;
int i;
QStringList headers;
QTableWidgetItem *nameItem;
QTableWidgetItem *pidItem;
QTableWidgetItem *ppidItem;
QTableWidgetItem *rssItem;
QTableWidgetItem *priorityItem;
pidNum=get_pid_info();
ui->tableWidget->setColumnCount(5);
ui->tableWidget->setRowCount(pidNum);
headers<<”进程名“<<”pid“<<”ppid“<<”内存占用/KB“<<”优先级“;
ui->tableWidget->setHorizontalHeaderLabels(headers);
for(i=0;i
{
nameItem=new QTableWidgetItem(QString::fromStdString(procInfo[i].name));
ui->tableWidget->setItem(i,0,nameItem);
nameItem->setTextAlignment(Qt::AlignCenter);
pidItem=new QTableWidgetItem(QString::fromStdString(procInfo[i].pid));
ui->tableWidget->setItem(i,1,pidItem);
pidItem->setTextAlignment(Qt::AlignCenter);
ppidItem=new QTableWidgetItem(QString::fromStdString(procInfo[i].ppid));
ui->tableWidget->setItem(i,2,ppidItem);
ppidItem->setTextAlignment(Qt::AlignCenter);
rssItem=new QTableWidgetItem(QString::fromStdString(procInfo[i].rss));
ui->tableWidget->setItem(i,3,rssItem);
rssItem->setTextAlignment(Qt::AlignCenter);
priorityItem=new QTableWidgetItem(QString::fromStdString(procInfo[i].priority));
ui->tableWidget->setItem(i,4,priorityItem);
华 中 科 技 大 学 课 程 设 计 报 告
priorityItem->setTextAlignment(Qt::AlignCenter);
}
ui->tableWidget->setColumnWidth(0,121);
ui->tableWidget->setColumnWidth(1,121);
ui->tableWidget->setColumnWidth(2,121);
ui->tableWidget->setColumnWidth(3,121);
ui->tableWidget->setColumnWidth(4,121);
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->tableWidget->setSelectionMode(QAbstractItemView::NoSelection);} void MainWindow::QueryProcess(){
QString queryitem;
int pidNum,i;
QStringList headers;
QTableWidgetItem *nameItem;
QTableWidgetItem *pidItem;
QTableWidgetItem *ppidItem;
QTableWidgetItem *rssItem;
QTableWidgetItem *priorityItem;
QHeaderView* headerView = ui->tableWidget_2->verticalHeader();
headerView->setHidden(true);//no row number
queryitem=ui->lineEdit->text();
pidNum=get_pid_info();
for(i=0;i
{
if(queryitem==QString::fromStdString(procInfo[i].name)|| queryitem==QString::fromStdString(procInfo[i].pid))
break;
}
ui->tableWidget_2->setColumnCount(5);
ui->tableWidget_2->setRowCount(1);
headers<<”进程名“<<”pid“<<”ppid“<<”内存占用/KB“<<”优先级“;
ui->tableWidget_2->setHorizontalHeaderLabels(headers);
nameItem=new QTableWidgetItem(QString::fromStdString(procInfo[i].name));
ui->tableWidget_2->setItem(0,0,nameItem);
nameItem->setTextAlignment(Qt::AlignCenter);
pidItem=new QTableWidgetItem(QString::fromStdString(procInfo[i].pid));
ui->tableWidget_2->setItem(0,1,pidItem);
pidItem->setTextAlignment(Qt::AlignCenter);
ppidItem=new QTableWidgetItem(QString::fromStdString(procInfo[i].ppid));
ui->tableWidget_2->setItem(0,2,ppidItem);
ppidItem->setTextAlignment(Qt::AlignCenter);
rssItem=new QTableWidgetItem(QString::fromStdString(procInfo[i].rss));
ui->tableWidget_2->setItem(0,3,rssItem);
rssItem->setTextAlignment(Qt::AlignCenter);
priorityItem=new QTableWidgetItem(QString::fromStdString(procInfo[i].priority));
ui->tableWidget_2->setItem(0,4,priorityItem);
priorityItem->setTextAlignment(Qt::AlignCenter);
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->tableWidget->setSelectionMode(QAbstractItemView::NoSelection);} void MainWindow::KillProcess(){
QString queryitem;
int pidNum,i;
华 中 科 技 大 学 课 程 设 计 报 告
int killtype=-1;
QString sudo;
char* command;
QByteArray ba;
queryitem=ui->lineEdit->text();
pidNum=get_pid_info();
for(i=0;i
{
if(queryitem==QString::fromStdString(procInfo[i].name)|| queryitem==QString::fromStdString(procInfo[i].pid))
break;
}
if(queryitem==QString::fromStdString(procInfo[i].name))
killtype=0;
if(queryitem==QString::fromStdString(procInfo[i].pid))
killtype=1;
switch(killtype){
case 0:
sudo=QString(”pkill %1“).arg(queryitem);
ba=sudo.toLatin1();
command=ba.data();
system(command);
break;
case 1:
sudo=QString(”kill %1“).arg(queryitem);
ba=sudo.toLatin1();
command=ba.data();
system(command);
break;
default:
break;
} } void MainWindow::CreateProcess(){
QProcess *pro=new QProcess;
QString newProc;
newProc=ui->lineEdit_2->text();
pro->start(newProc);} void MainWindow::add_point(float cpuRate){
int i;
int size=yList.size();
int y=cpuRate;
if(size>120)
{
yList.pop_front();
}
if(size==0)
{
for(i=0;i<119;i++)
{
yList.push_back(0);
}
}
华 中 科 技 大 学 课 程 设 计 报 告
if(size>=1)
{
yList.push_back(y);
emit UpdateCPULine();
}
else{
yList.push_back(y);
} } void MainWindow::UpdateCPULine(){
int count=0;
QPixmap pix(600,160);
QPainter painter(&pix);
pix.fill(Qt::blue);
QPen pen0;
pen0.setColor(Qt::lightGray);
painter.setPen(pen0);
for(int i=1;i<4;i++)
{
painter.drawLine(0,i*40,600,i*40);
}
QPen pen;
pen.setColor(Qt::red);
pen.setWidth(2);
painter.setPen(pen);
while(count<(yList.size()-1))
{
painter.drawLine(5*count,160-1.6*(yList.value(count)),5*(count+1),160-1.6*(yList.value(count+1)));
count++;
}
ui->cpuline_label->setPixmap(pix);} void MainWindow::add_point_mem(float memRate){
int i;
int size=yList1.size();
int y=memRate;
if(size>120)
{
yList1.pop_front();
}
if(size==0)
{
for(i=0;i<119;i++)
{
yList1.push_back(0);
}
}
if(size>=1)
{
yList1.push_back(y);
emit UpdateMemLine();
}
华 中 科 技 大 学 课 程 设 计 报 告
else{
yList1.push_back(y);
} } void MainWindow::UpdateMemLine(){
int count=0;
QPixmap pix(600,160);
QPainter painter(&pix);
pix.fill(Qt::blue);
QPen pen0;
pen0.setColor(Qt::lightGray);
painter.setPen(pen0);
for(int i=1;i<4;i++)
{
painter.drawLine(0,i*40,600,i*40);
}
QPen pen;
pen.setColor(Qt::red);
pen.setWidth(2);
painter.setPen(pen);
while(count<(yList1.size()-1))
{ painter.drawLine(5*count,160-1.6*(yList1.value(count)),5*(count+1),160-1.6*(yList1.value(count+1)));
count++;
}
ui->memlinelabel->setPixmap(pix);}
#main.cpp,新建主窗口并显示
#include ”mainwindow.h" #include
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();} 心得体会
本次课程设计,第一个题目很简单,以前写过文件拷贝的C语言程序,第一个题目在以前的基础上用open、read、write等替换fopen、fread、fwrite即可;第二个题目和第三个题目是第一次遇见,在此之前对系统调用和设备驱动程序的知识知之甚少,所以刚开始障碍比较大,但是慢慢地就有了些了解,也就没那么复杂了,但是需要细心;第四个题目看起来很复杂,其实没那么复杂,第一题已经解决了Qt
华 中 科 技 大 学 课 程 设 计 报 告 的使用问题,剩下的就是对/proc文件系统的处理问题,包括文件的读取、读取之后对字符串的处理等,这些处理相对来说比较繁琐,所以花费了不少时间。
这次课设让我对Linux的系统调用、设备驱动程序的工作原理、/proc文件系统等有了更深的理解,对Qt的使用比以前更加熟练。总而言之,这次课设让我收获很多,受益匪浅。
第四篇:操作系统课设程序源
南京工程学院
课程设计报告
课 程 名 称 操作系统原理与应用 实 验 名 称 储存管理 院(系、部、中心)
通信工程学院
专
业
通信工程
班 级 信息工程111 姓 名 车含喆 学 号 208110808 起 止 日 期 2014.4.22 指 导 教 师 耿鹏
1、实验目的
1.通过模拟实现请求页式存储管理的几种基本页面置换算法。2.了解虚拟存储技术的特点
3.掌握虚拟存储请求页式存储管理中几种基本页面置换算法的基本思想和实现过程,并比较它们的效率。
2、实验内容
3、实验设备
PC 1台,Ubuntu 操作系统
4、实验总结
UNIX中,为了提高内存利用率,提供了内外存进程对换机制;内存空间的分配和回收均以页为单位进行;一个进程只需将其一部分调入内存便可运行;还支持请求调页的储存管理方式。
5.实验程序
#include
};typedef struct pfc_struct pfc_type;pfc_type pfc[total_vp],*freepf_head,*busypf_head,*busypf_tail;int diseffect, a[total_instruction];int page[total_instruction],offset[total_instruction];int initialize(int);int FIF0(int);int LRU(int);int LFU(int);int NUR(int);int OPT(int);int pn,pfn;struct pfc_struct *next;
int main(){ int s,j,i;srand(10*getpid());s=(float)319*rand()/32767/32767/2+1;
for(i=0;i } int initialize(total_pf)int total_pf;{ int i;diseffect=0;for(i=0;i { } for(i=0;i } return 0;LRU(i);OPT(i); } pfc[i].next=&pfc[i+1];pfc[i].pfn=i;pfc[total_pf-1].next=NULL; } int FIFO(total_pf)int total_pf;{ int i,j;pfc_type *p;initialize(total_pf);busypf_head=busypf_tail=NULL;for(i=0;i } printf(“FIFO:%6.4fn”,1-(float)diseffect/320);return 0;if(pl[page[i]].pfn==INVALID){ diseffect+=1;if(freepf_head==NULL){ p=busypf_head==NULL;pl[busypf_head->pn].pfn=INVALID;freepf_head=busypf_head;freepf_head->next=NULL;busypf_head=p;} p=freepf_head->next;freepf_head->next=NULL;freepf_head->pn=page[i];pl[page[i]].pfn=freepf_head->pfn;if(busypf_tail==NULL)busypf_head=busypf_tail=freepf_head;else { } freepf_head=p;} busypf_tail->next=freepf_head;busypf_tail=freepf_head;pfc[total_pf-1].pfn=total_pf-1;freepf_head=&pfc[0];return 0; } int LRU(total_pf)int total_pf;{ int min,minj,i,j,present_time;initialize(total_pf);present_time=0;for(i=0;i } if(pl[page[i]].pfn==INVALID){ } else pl[page[i]].time=present_time;diseffect++;if(freepf_head=NULL){ } pl[page[i]].pfn=freepf_head->pfn;pl[page[i]].time=present_time;freepf_head=freepf_head->next;min=32767;for(j=0;j if(min>pl[j].time&&pl[j].pfn!=INVALID){ } min=pl[j].time;minj=j;freepf_head=&pfc[pl[minj].pfn];pl[minj].pfn=INVALID;pl[minj].time=-1;freepf_head->next=NULL;present_time++;printf(“LRU:%6.4fn”,1-(float)diseffect/320);} int OPT(total_pf)int total_pf;{ int i,j,max,maxpage,d,dist[total_vp]; pfc_type *t;initialize(total_pf);for(i=0;i } freepf_head->next=NULL;pl[maxpage].pfn=INVALID;} diseffect++;if(freepf_head==NULL){ for(j=0;j 实验一 一、实验名称 进程调度的设计与实现 二、实验目的1、综合应用下列知识点设计并实现操作系统的进程调度:邻接表,布尔 数组,非阻塞输入,图形用户界面GUI,进程控制块,进程状态转换,多级反馈队列进程调度算法。 2、加深理解操作系统进程调度的过程。 3、加深理解多级反馈队列进程调度算法。 三、实验内容与主要设计思想 1、采用一种熟悉的语言,如C、PASCAL或C++等,编制程序。 2、采用多级反馈队列调度算法进行进程调度。 3、每个进程对应一个PCB。在PCB中包括进程标识符pid、进程的状态 标识status、进程优先级priority、进程的队列指针next和表示进程生命周期的数据项life(在实际系统中不包括该项)。 4、创建进程时即创建一个PCB,各个进程的pid都是唯一的,pid是在1 到100范围内的一个整数。可以创建一个下标为1到100的布尔数组,“真”表示下标对应的进程标识号是空闲的,“假”表示下标对应的进程标识号已分配给某个进程。 5、进程状态status的取值为“就绪ready”或“运行run”,刚创建时,状态为“ready”。被进程调度程序选中后变为“run”。 6、进程优先级priority是0到49范围内的一个随机整数。 7、进程生命周期life是1到5范围内的一个随机整数。 8、初始化时,创建一个邻接表,包含50个就绪队列,各就绪队列的进 程优先级priority分别是0到49。 9、为了模拟用户动态提交任务的过程,要求动态创建进程。进入进程调 度循环后,每次按ctrl+f即动态创建一个进程,然后将该PCB插入就绪队列中。按ctrl+q退出进程调度循环。 10、在进程调度循环中,每次选择优先级最大的就绪进程来执行。将 其状态从就绪变为运行,通过延时一段时间来模拟该进程执行一个时 间片的过程,然后优先级减半,生命周期减一。设计图形用户界面GUI,在窗口中显示该进程和其他所有进程的PCB内容。如果将该运行进程的生命周期不为0,则重新把它变为就绪状态,插入就绪队列中;否则该进程执行完成,撤消其PCB。以上为一次进程调度循环。 11、在上机实现该程序之后,要求写出实验报告,其中包括实验名称、实验目的、实验内容、程序的主要流程图、实验心得和主要源程序清单等。 四、操作系统综合性、设计性实验课程介绍 (1)课程简介与要求 《操作系统》是计算机专业学生的必修课程,该课程要求以计算机 组成原理、数据结构、PASCAL语言程序设计(或C语言程序设计)作为先行课程。课程的教学目标是:使学生学习和掌握操作系统的主要功能、基本原理、主要算法和实施技术,懂得操作系统在现 代计算机系统中的重要作用,具有分析实际操作系统的基本能力。 (2)实验目的及要求 巩固和加深对操作系统相关知识的理解;掌握模拟的实验方法;提 高编程能力。 (3)实验方式与要求 根据在操作系统课程所学的理论,采用模拟的方法编程实现操作系 统的某些功能,上机调试通过,并提交实验报告。 (4)考试方法及评分 上机检查与批改实验报告相结合,占总评成绩的20%到30%。 (5)主要仪器设备 台式电脑。 (6)教材及参考书 教材: 《计算机操作系统教程》张尧学等,清华大学出版社,2006年10月第3版 主要参考书: 《UNIX操作系统教程》尤晋元,西北电讯工程学院出版社,198 5年 《操作系统》冯耀霖等,西安电子科技大学出版社,1994年 《操作系统原理》尤晋元,上海交大出版社,1984年 《计算机操作系统》汤子瀛等,西安电子科技大学出版社,1996年12月第一版 [附录一]实验报告的格式 实验课程:操作系统 实验名称:进程调度的设计与实现(综合实验)第一部分 实验内容 1.实验目标 1、综合应用下列知识点设计并实现操作系统的进程调度:邻接表,布尔 数组,非阻塞输入,图形用户界面GUI,进程控制块,进程状态转换,多级反馈队列进程调度算法。 2、加深理解操作系统进程调度的过程。 3、加深理解多级反馈队列进程调度算法。 2.实验任务 1、用一种熟悉的语言,如C、PASCAL或C++等,编制程序。 2、采用多级反馈队列调度算法进行进程调度。 3.实验设备及环境 PC;C/C++等编程语言。 4.实验主要步骤 (1)根据实验目标,明确实验的具体任务; (2)编写程序实现进程调度算法; (3)设计实验数据并运行程序、记录运行的结果; (4)分析实验结果; (5)实验后的心得体会。 第二部分 问题及算法 1.问题描述(学生填) 2.多级反馈队列进程调度算法的一般思路(学生填) 3.算法实现的关键点(学生填) 第三部分 实验结果与分析 1.实验数据及结果(学生填) 2.实验分析及结论(学生填) 第四部分 心得与展望 1.自我评价及心得体会(学生填) 2.展望(学生填) 第五部分 附录 1.主要界面(学生填) 2.源程序(学生填) 参考文献(学生填) 实验二 一、实验名称 模拟操作系统的页面置换 二、实验目的1、掌握操作系统的页面置换过程,加深理解页式虚拟存储器的实现原理。 2、掌握用随机数生成满足一定条件的指令地址流的方法。 3、掌握页面置换的模拟方法。 三、实验要求与提示 1、采用一种熟悉的语言,如C、PASCAL、C++或Java等,编制程序。 2、模拟操作系统采用OPT、FIFO和LRU算法进行页面置换的过程。 3、设程序中地址范围为0到32767,采用随机数生成256个指令地址,满足50%的地址是顺序执行,25%向前跳,25%向后跳。为满足上述条件,可采取下列方法:设d0=10000,第n个指令地址为dn,第n+1个指令地址为dn+1,n的取值范围为0到255。每次生成一个1到1024范围内的随机数a,如果a落在1到512范围内,则dn+1=dn+1。如果a落在513到768范围内,则设置dn+1为1到dn范围内一个随机数。如果a落在769到1024范围内,则设置dn+1为dn到32767范围内一个随机数。 4、页面大小的取值范围为1K,2K,4K,8K,16K。按照页面大小将指令地址转化为页号。对于相邻相同的页号,合并为一个。 5、分配给程序的内存块数取值范围为1块,2块,直到程序的页面数。 6、分别采用OPT、FIFO和LRU算法对页号序列进行调度,计算出对应的缺页中断率。 7、打印出页面大小、分配给程序的内存块数、算法名、对应的缺页中断率。 8、分析页面大小和分配给程序的内存块数对缺页中断率的影响。分析不同的页面置换算法的调度性能。 9、在上机实现该程序之后,要求写出实验报告,其中包括实验名称、实验目的、实验内容、程序的主要流程图、实验心得和主要源程序清单等。第五篇:操作系统本科实验任务