第一篇:操作系统课设程序源
南京工程学院
课程设计报告
课 程 名 称 操作系统原理与应用 实 验 名 称 储存管理 院(系、部、中心)
通信工程学院
专
业
通信工程
班 级 信息工程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)可根据需要输入当前磁头的位置,磁头移动方向;(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的使用比以前更加熟练。总而言之,这次课设让我收获很多,受益匪浅。 一、操作系统课程设计要求: 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.问题描述 实现大整数(200位以内的整数)的加、减、乘、除运算。2.设计要求 设计程序实现两个大整数的四则运算,输出这两个大整数的和、差、积、商及余数。 3.数据结构 本课程设计采用顺序串来实现。4.问题分析 由于整数数据存储位数有限,因此引入串的概念,将整型数据用字符串进行存储,利用字符串的一个字符存储大整数的一位数值,然后根据四则运算规则,对相应位依次进行相应运算,同时保存进位,从而实现大整数精确的运算。具体设计思路如下: (1)计算大整数加法时,采用数学中列竖式的方法,从个位(即字符串的最后一个字符)开始逐位相加,超过或达到10则进位,同时将该位计算结果存到另一个字符串中,直至加完大整数的所有位为止。 (2)计算大整数减法时,首先调用库函数strcmp判断这两个大整数是否相等,如果相等则结果为0,否则用compare函数判断被减数和减数的大小关系,进而确定结果为正数还是负数,然后对齐位依次进行减法,不够减则向前借位,直至求出每一位减法之后的结果。 (3)计算大整数乘法时,首先让乘数的每一位都和被乘数进行乘法运算,两个乘数之积与进位相加作为当前位乘积,求得当前位的同时获取进位值,进而实现大整数的乘法运算。 (4)计算大整数除法时,类似做减法,基本思想是反复做减法,从被除数里最多能减去多少次除数,所求得的次数就是商,剩余不够减的部分则是余数,这样便可计算出大整数除法的商和余数。 需求分析(1)任何一个表达式都是由操作数、运算符和界限符组成的,我们称之为单词.(2)表达式求值首先要符合四则运算规则: ① 先乘除,后加减 ② 从左到右进行运算 ③ 先括号内,后括号外(3)功能实现: ① 若当前单词为数字串,则压入数值栈 ② 若当前单词为运算符并大于运算栈的栈顶符号,则进栈 ③ 若当前单词为运算符并等于运算栈的栈顶符号,去括号,输出 ④ 若当前单词为运算符并小于运算栈的栈顶符号,则进行运算 课程设计的目的 通过课程设计全面掌握《C语言程序设计》关键知识点,掌握C语言中数组、指针、结构体、文件等方面的基本知识。 通过课程设计了解并掌握C语言程序设计的方法,熟悉C程序设计的开发环境及C程序的 调试过程。 培养学生查阅参考资料、手册的自学能力,通过独立思考深入钻研有关问题,学会自己分析、解决问题的方法。 课程设计的任务和要求 任务: 编程求出输入的两个正整数之和,这两个正整数的可能达到200位。 要求: 输入: 共有两行,第一行为第1个正整数;第二行为第2个正整数。 输出: 2个正整数之和。 主要参与成员 姓 名 学 号 系 别 班 级 主要作用(分工) 成果形式 设计 软件 作品 其他: 完成情况及以后的拓展设想 通过用C语言编写函数基本实现了大整数相加这个程序,但该程序仍存在一些不足,还可以加上一些语句使程序具有容错功能,并且可以正确计算一个负数和一个正数相加。 课 程 设 计 鉴 定 情 况 表 小组鉴定意见 小组长签名: 年 月 日 指导教师意见 教师签名: ****年**月**日 课程设计成绩 优 良 及格 不及格 教研室意见 年 月 日 备注 《C语言程序设计》课程设计报告书 作者:廖 序 课程设计概述 课程设计名称 大整数相加 任务要求: 编程求出输入的两个正整数之和,这两个正整数的可能达到200位。 输入: 共有两行,第一行为第1个正整数;第二行为第2个正整数。 输出: 2个正整数之和。开发环境: C语言。C语言是目前世界上流行、使用最广泛的高级程序设计语言。1972年,C语言在美国贝尔实验室里问世,后来又被多次改进,并出现了多种版本。80年代初,美国国家标准化协会(ANSI),根据C语言问世以来各种版本对C语言的发展和扩充,制定了ANSIC标准。 目前,在微机上广泛使用的C语言编译系统有MicrosoftC、Turbo C、Borland C等。这些C语言版本不仅实现了ANSIC标准,而且在此基础上各自作了一些扩充,使之更加方便、完美。 C语言的特点: C语言是一种结构化语言。它层次清晰,便于按模块化方式组织程序,易于调试和维护。C语言的表现能力和处理能力极强。它不仅具有丰富的运算符和数据类型,便于实现各类复杂的数据结构。它还可以直接访问内存的物理地址,进行位(bit)一级的操作。 由于C语言实现了对硬件的编程操作,因此C语言集高级语言和低级语言的功能于一体。既可用于系统软件的开发,也适合于应用软件的开发。 此外,C语言还具有效率高,可移植性强等特点。因此广泛地移植到了各类各型计算机上,从而形成了多种版本的C语言。 参考资料 李铮、叶艳冰、汪德俊,C语言程序设计基础与应用,清华大学出版社,2005 [2]CSDN技术中心 二、概要设计 为了实现大整数相加这个程序,将程序划分为了三个模块: 输入数据。运算。输出结果。 首先定义了子函数Input()来存储用户输入的两个加数,为了满足任意位数的两个大整数相加,在子函数Input()中嵌套调用子函数Init()使sum数组里面存放的数初始化为”0”。 然后定义子函数Long_Add()使两个大整数作加法运算,从后面往前面相加,附带进位。定义子函数Output()实现输出结果。 最后如下图所示,在主函数main中调用Input(),Long_Add(),Output()三个子函数实现程序。 三、详细设计 程序的流程图: 四、调试过程 第一次 测试数据a=***7,b=111111 编译运行后不能输出结果,检查函数后编译正确。再次分析,发现如果直接把a,b,sum定义为unsigned int型的话,计算出来的和的范围只能在0~65535之间,否则就会出现错误。尝试将a,b,sum存放到字符数组中,从个位开始,一位一位相加。 第二次 测试数据a=***7,b=111111 编译运行后仍不能输出结果。分析原因,在用于输出的子函数Output()中,输出数组字符数组sum[]前未确定和的最高非零位。 尝试加入for(i=0;i 第三次 测试数据a=99999919,b=99 编译运行后发现计算出来结果不正确。经过分析,函数中没有对最后 一个进位进行处理。 尝试加入while(carry > 0)语句,再次进行调试。 { tempsum = sum[i]-'0'+carry;sum[i] = tempsum%10+'0';carry = tempsum/10;i--;} 第四次 测试数据a=99999919,b=99 编译运行后得到正确结果。 第五次 随意输入几组数据进行测试,结果都是正确的。程序得到实现。 五、结论与体会 通过不断的调试、修改,本课程设计最终实现了200位以内的两个大整数相加,但程序还 可以进一步完善,程序中仍存在一些不足之处,比如缺少容错功能,不能准确计算负整数加正整数,等等问题 虽然C语言程序设计在上学期做为我们的必修课已经学习过了,但书到用时方恨少,这次课程设计的学习程序设计中暴露出的我自身的问题更是非常明显。 一开始看到题目认为非常简单,直接将两个数都定义为整型。编写程序并运行后发现并不能达到题目的要求,计算出来的和只能小于等于65535,否则就会出现错误。分析后,将数据作为字符串来处理,用for循环语句从存数的字符数组中一位一位的取数出来,按照数位对齐,从个位开始,按位相加,逢十进一的运算规则进行运算。最后用字符输出函数putchar()输出计算出来的结果。由于程序偏大且较复杂,将程序划分为了输入数据、运算、输出数据三个子程序。数次编译调试后,最终使程序得以实现。 经过三个星期的上机实践学习,使我对C语言有了更进一步的认识和了解,让我能够进一步的掌握和运用C语言来编写程序。要想学好C语言要重在实践,要通过不断的上机操作才能更好地学习它,通过实践,我也发现我的好多不足之处和薄弱环节。 首先,基础掌握不牢固,对于C语言中的许多基本语法尚没有熟练掌握,在设计过程中仍需请教其它同学,查阅课本,设计效率很低。 其次,经典算法掌握不牢。在完成作业的过程中还需查阅书籍和借鉴他人。 再次,程序量过大的时候,头绪理不清。杂乱无章,无系统性,不便调试和阅览,自己也易于出错。 并且对C语言中经常出现的错误也不了解,通过实践,使我在这几个方面的认识有所提高。 通过实践的学习,我认到学好计算机要重视实践操作,不仅仅是学习C语言,还是其它的语言,以及其它的计算机方面的知识都要重在实践,所以后在学习过程中,我会更加注视实践操作,使自己便好地学好计算机。 六、源程序清单 #include t;string.h> #define Max 1000 char sum[Max+1];/*和*/ char a[Max],b[Max];/*两个加数*/ int len1,len2;void Input(char a[],char b[]){ int i,len;void Init(char a[]);/*对Init()函数进行声明*/ printf(“Please enter two integer:n”);scanf(“%s %s”,a,b);len1=strlen(a);len2=strlen(b);Init(sum);len=strlen(a);for(i=len-1;i>=0;i--)sum[Max+i-len] = a[i];} void Init(char a[]) { int i;for(i=0;i void Long_Add(char sum[],char new[]){ int i,j;int len;int tempsum;int carry = 0;/*进位*/ len = strlen(new);/*从个位开始,按位相加,逢十进一*/ for(i=Max-1,j=len-1;i>=0,j>=0;i--,j--){ tempsum = sum[i]-'0'+new [j]-'0'+carry;sum[i] = tempsum%10+'0';carry = tempsum/10;} while(carry > 0)/*处理最后一个进位*/ { tempsum = sum[i]-'0'+carry;sum[i] = tempsum%10+'0';carry = tempsum/10;i--;} return;} void Output(char sum[]){int i,n;/*寻找和的最高非零位*/ for(i=0;i Long_Add(sum,b);Output(sum);getch();return 0;第二篇:操作系统课设
第三篇:操作系统课设
第四篇:操作系统课设任务
第五篇:数据结构课设