![计算机操作系统-课设-操作系统课设报告_第1页](http://file4.renrendoc.com/view9/M03/30/35/wKhkGWccc2WAaKn7AACgYzSTBe8720.jpg)
![计算机操作系统-课设-操作系统课设报告_第2页](http://file4.renrendoc.com/view9/M03/30/35/wKhkGWccc2WAaKn7AACgYzSTBe87202.jpg)
![计算机操作系统-课设-操作系统课设报告_第3页](http://file4.renrendoc.com/view9/M03/30/35/wKhkGWccc2WAaKn7AACgYzSTBe87203.jpg)
![计算机操作系统-课设-操作系统课设报告_第4页](http://file4.renrendoc.com/view9/M03/30/35/wKhkGWccc2WAaKn7AACgYzSTBe87204.jpg)
![计算机操作系统-课设-操作系统课设报告_第5页](http://file4.renrendoc.com/view9/M03/30/35/wKhkGWccc2WAaKn7AACgYzSTBe87205.jpg)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
课程设计报告题目:操作系统课程设计课程名称:操作系统专业班级:信息安全1302学号: 姓名:指导教师:报告日期:2016年3月17日计算机科学与技术学院目录TOC\o"1-3"1 文件拷贝、多窗口进程并发 31.1 课设内容 31.2 课设要求 31.3 具体实现 31.3.1 文件拷贝 31.3.2 多窗口进程并发 51.4 测试结果 51.4.1 文件拷贝 51.4.2 多窗口进程并发 71.5 源代码 72 增加系统调用、编译内核 102.1 课设内容 102.2 课设要求 102.3 实验环境 102.4 具体实现 102.4.1 系统调用的原理 102.4.2 编写新的系统调用程序 102.4.3 编译内核 112.5 测试结果 132.6 源代码 143 增加字符设备驱动程序 153.1 课设内容 153.2 课设要求 153.3 具体实现 153.3.1 模块机制 153.3.2 Makefile 163.3.3 安装设备驱动 163.4 测试结果 164 系统监控器 184.1 课设内容 184.2 UI设计 184.3 主要功能实现 204.3.1 获取并显示主机名 204.3.2 显示系统当前时间、持续时间和启动时间 214.3.3 显示系统的版本号 234.3.4 显示cpu的型号和主频大小 254.3.5 显示所有进程的信息 274.3.6 通过pid或进程名查询或杀死进程 324.3.7 显示当前内存和交换分区使用情况 424.3.8 显示当前CPU使用率 464.3.9 cpu和内存使用率的图形化显示 494.3.10 关机和重启 514.3.11 作者信息 514.4 全局效果 525 课设感悟 55文件拷贝、多窗口进程并发课设内容掌握Linux操作系统的使用方法,包括键盘命令、系统调用;掌握在Linux下的编程环境。课设要求编写一个C程序,其内容为实现文件拷贝的功能。编写一个C程序,其内容为分窗口同时显示三个并发进程的运行结果。要求用到Linux下的图形库(GTK/Qt)。具体实现文件拷贝在windows操作系统上实现的文件拷贝功能一般使用fopen、fread、fwrite三个来自标准C函数库的函数执行对文件的打开、读、写操作,而本次实验要求使用Linux系统的系统调用open、read、write实现上述三个操作。具体设计思路如下:打开两个文件(分别是源文件和目标文件,可以是任意字符流形式存储的文件,包括文本文件、照片等),调用read函数读取源文件的内容,将read的返回值作为while循环的判断条件,当返回值大于0(即还未读取完毕源文件中的内容)时,调用write执行向目标文件写的操作,否则跳出循环,表示源文件已经被拷贝到目标文件,然后调用close关闭源文件和目标文件。涉及到的主要系统调用如下:open()函数函数定义: intopen(constchar*pathname,intflags);参数说明: 参数pathname指向欲打开的文件路径字符串。下列是参数flags所能使用的标志位:O_RDONLY以只读方式打开文件O_WRONLY以只写方式打开文件O_RDWR以可读写方式打开文件。上述三种标志位是互斥的,也就是不可同时使用,但可与下列的标志位利用OR(|)运算符组合。O_CREAT若欲打开的文件不存在则自动建立该文件。O_EXCL如果O_CREAT也被设置,此指令会去检查文件是否存在。文件若不存在则建立该文件,否则将导致打开文件错误。此外,若O_CREAT与O_EXCL同时设置,并且欲打开的文件为符号连接,则会打开文件失败。O_NOCTTY如果欲打开的文件为终端机设备时,则不会将该终端机当成进程控制终端机。O_TRUNC若文件存在并且以可写的方式打开时,此标志位会令文件长度清为0,而原来存于该文件的资料也会消失。O_APPEND当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面。O_NONBLOCK以不可阻断的方式打开文件,也就是无论有无数据读取或等待,都会立即返回进程之中。O_NDELAY同O_NONBLOCK。O_SYNC以同步的方式打开文件。O_NOFOLLOW如果参数pathname所指的文件为一符号连接,则会令打开文件失败。O_DIRECTORY如果参数pathname所指的文件并非为一目录,则会令打开文件失败。read()函数函数定义:ssize_tread(intfd,void*buf,size_tcount);参数说明:count是请求读取的字节数,读上来的数据保存在缓冲区buf中,同时文件的当前读写位置向后移。返回值: 成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0。write()函数函数定义: ssize_twrite(intfd,void*buf,size_tcount);参数说明: write()会把参数buf所指内存写入count个字节到参数fd所指的文件内。文件读写位置也会随之移动。返回值: 如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入error中。多窗口进程并发本实验需要的图形库是跨平台的开发工具Qt。实现的功能很简单,即运行主程序后可以弹出三个进程的可视化窗口。三个窗口都是在Qt中使用widget窗口类实现,上面分别显示出“Process1”、“Process2”和“Process3”。在主程序中,使用三次fork()函数分别创建三个子进程,其中“Process2”是“Process1”的子进程,“Process3”是“Process2”的子进程,每个子进程中都使用execv()函数执行其对应的可视化窗口的可执行文件。测试结果文件拷贝首先,创建一个源文件1.txt,其内容为“helloworld!”,如图1.1所示。图1.1源文件内容之后创建一个新的目的文件2.txt,内容为空,如图1.2所示。图1.2新建目的文件 通过终端进入正确的目录,编译并执行文件拷贝程序copy,终端显示出字符串“Success”,表示拷贝成功,如图1.3所示。图1.3执行文件拷贝命令行 再次查看目的文件2.txt,发现拷贝已成功,如图1.4所示。图1.4拷贝成功多窗口进程并发编译并执行包含有创建三个子进程的main.c文件,即可显示出三个子进程所对应的可视化窗口,每个窗口上显示出这是第几个进程,效果如图1.5所示。图1.5多窗口进程并发效果源代码文件拷贝#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<stdio.h>#defineSIZE1024intmain(intargc,char*argv[]){intfile1,file2;//文件描述符intnum_read,num_write;intnum_read,num_write;charbuffer[SIZE];if(argc!=3){printf("Inputformatisillegal!\n");return0;}/*打开源文件*/if((file1=open(argv[1],O_RDONLY))==-1){printf("Openerror!\n");return0;}/*创建目标文件*/if((file2=open(argv[2],O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1){printf("Openerror!\n");return0;}/*实现文件拷贝*/while((num_read=read(file1,buffer,sizeof(buffer)))>0){num_write=write(file2,buffer,num_read);}printf("Success!\n");close(file1);close(file2);return1;}多窗口进程并发#include<stdio.h>#include<unistd.h>#include<sys/types.h>#include<sys/wait.h>voidmain(){intstatus;pid_tp1,p2,p3;/*创建三个子进程*/if((p1=fork())==0)execv("./widget1",NULL);elseif((p2=fork())==0)execv("./widget2",NULL);elseif((p3=fork())==0)execv("./widget3",NULL);/*等待子进程结束*/waitpid(p1,(int*)0,WIFEXITED(&status));waitpid(p2,(int*)0,WIFEXITED(&status));waitpid(p3,(int*)0,WIFEXITED(&status));exit(0);}增加系统调用、编译内核课设内容掌握系统调用的实现过程,通过编译内核方法,加一个新的系统调用,另编写一个应用程序,调用新增加的系统调用。课设要求内核编译、生成,使用新内核启动;增系统调用实现:文件拷贝或P、V操作。实验环境硬件环境:MacBookAir13-inch4GBMemory1.3GHzCorei5操作系统:Ubuntu64位15.10原配内核:Linux-4.2.0-16-generic新编译内核:Linux-3.18.27具体实现系统调用的原理用户进程不能访问内核所占内存空间,也不能调用内核函数。进程调用一个特殊的指令,这个指令会跳到一个事先定义的内核中的一个位置。在IntelCPU中,由中断INT0x80实现。(与DOS功能调用int0x21很相似)跳转到的内核位置叫做sysem_call。检查系统调用号,这个号码代表进程请求哪种服务。然后,它查看系统调用表(sys_call_table)找到所调用的内核函数入口地址。接着,就调用函数,等返回后,做一些系统检查,最后返回到进程(如果这个进程时间用尽,就返回到其他进程)。编写新的系统调用程序新的系统调用程序实现的功能是:将一个文件中的内容拷贝到另一个文件中。这个系统调用的参数是两个char*型的字符指针SourceFile、GoalFile,分别表示源文件和目标文件的路径名。用户进程中的open、read、write、close函数此时对应内核函数sys_open、sys_read、sys_write、sys_close函数。循环拷贝的判断条件还是sys_read的返回值,当其大于0的时候执行循环,否则表示源文件已拷贝到了目标文件。mm_segment_t类型的变量fs的作用是在读写文件前得到当前fs,避免使用的缓冲区超过了用户空间的地址范围而报错。编译内核下载新的内核压缩包linux-3.18.27.tar.xz,解压到/usr/src/文件夹下;进入目录/usr/src/linux-3.18.27;添加系统调用函数,修改文件/kernel/sys.c如图2.1所示;图2.1添加系统调用添加系统调用号:322,修改文件/arch/x86/syscalls/syscall_64.tbl,如图2.2所示;图2.2添加系统调用号添加声明到头文件,修改文件/include/linux/syscalls.h如图2.3所示;图2.3添加头文件声明在编译内核之前先要安装ncurses库,进入超级用户状态,使用命令#apt-getinstalllibncurses5-dev安装;#makemrproper净化解压后的源代码;#makemenuconfig对内核选项进行配置;#makeclean删除配置时留下的一些不用的文件;#make-j4编译内核和内核模块,使用多线程加速编译;#makemodules_install安装内核模块;#makeinstall安装内核;由于使用虚拟机,需输入命令:mkinitramfs-o/boot/initrd.img-3.18.27;在终端内使用vim对文件/boot/grub/grub.cfg进行修改,将其中的settimeout_style=hidden改为=menu,将settimeout=o改为=30,如图2.4所示,这样可以使系统启动时可以显示出选择内核的菜单;图2.4修改文件以显示引导菜单重新启动,选择进入linux-3.18.27内核即可。测试结果进入目录,目录中的文件如图2.5所示:图2.5目录中的文件 1.txt中的内容为“helloworld!”,编译并执行test测试程序,即可完成将1.txt的内容拷贝到2.txt中,如图2.6所示。图2.6测试程序成功源代码#include<linux/unistd.h>#include<stdio.h>#include<stdlib.h>#include<asm/unistd.h>intmain(intargc,char*argv[]){intb=syscall(322,argv[1],argv[2]);printf("%d\n",b);return0;}增加字符设备驱动程序课设内容掌握增加设备驱动程序的方法。通过模块方法,增加一个新的设备驱动程序,其功能可以简单。课设要求实现字符设备的驱动——可以输出所输入的字符串。具体实现模块机制Linux核心是一种monolithic类型的内核,即单一的大核心,另外一种形式是MicroKernel,核心的所有功能部件都被拆成独立部分,这些部分之间通过严格的通讯机制进行联系。Linux内核是一个整体结构,因此向内核添加任何东西或者删除某些功能,都十分困难。为了解决这个问题,引入了模块机制,从而可以动态的在内核中添加或者删除模块。模块一旦被插入内核,就和内核其他部分一样。Linux内核中的设备驱动程序是一组常驻内存的具有特权的共享库,是低级硬件处理例程。对用户程序而言,设备驱动程序隐藏了设备的具体细节,对各种不同设备提供了一致的接口,一般来说是把设备映射为一个特殊的设备文件,用户程序可以像对其它文件一样对此设备文件进行操作。Linux支持3种设备:字符设备、块设备和网络设备。设备由一个主设备号和一个次设备号标识。主设备号唯一标识了设备类型,即设备驱动程序类型,它是块设备表或字符设备表中设备表项的索引。次设备号仅由设备驱动程序解释,一般用于识别在若干可能的硬件设备中,I/O请求所涉及到的那个设备。典型的Linux模块实现机制有如下几步:注册设备:在系统初启或者加载模块的时候,必须将设备登记到相应的设备数组,并返回主设备号。定义功能函数:对于每一个驱动函数来说,都有一些和此设备密切相关的功能函数。以最常用的块设备或者字符设备来说,都存在着诸如open()、read()这一类的操作。当系统调用这些调用时,将自动的使用驱动函数中特定的模块来实现具体的操作。卸载设备:在不用这个设备时,可以将它卸载,主要是从/proc中取消这个设备的特殊文件。MakefileMakefile文件用于编译设备驱动程序,其代码采用的是PPT给出的通用代码,这里不再进行赘述,也不在源代码中列出。安装设备驱动从终端进入存放着设备驱动程序和Makefile文件的目录;输入make命令,编译设备驱动程序,可以在目录中看到生成了各种配置文件,包括后缀名为.ko的模块文件;输入insmod–fmydevice.ko,加载生成mydevice.ko模块;输入cat/proc/devices,获取设备驱动程序的主设备号;输入mknod/dev/mydevicec测试结果按照上述步骤完成对驱动设备的编译后,就可以在该目录下看到生成的诸多设备文件和配置文件,如图3.1所示;图3.1编译完成后生成的文件在终端进入测试程序所在的目录,编译并运行测试程序,如图3.2所示;图3.2编译并运行测试程序按照提示输入“hello”,则设备输出的字样也为“hello”,如图3.3所示,测试成功。图3.3测试结果系统监控器课设内容了解/proc文件的特点和使用方法;监控系统状态,显示系统中若干部件使用状态;用图形界面实现系统监控状态。UI设计在最开始做的时候,我是将所有需要展示出的关于进程的项目(如进程号、名称、占用内存、父进程号等等)都呈现在一张列表(ListWidget)中,但我发现由于项目过多,横向查看起来很不方便,所以我借鉴了苹果Mac系统的活动监视器界面,如图4.1所示。图4.1Mac系统的活动监视器 可以看到,虽然都是展示有关进程的信息,但它将这些信息项分散到几个不同的页里,如将CPU占有率放在CPU页,而将内存使用率放在内存页等,这样不仅方便了查看,也腾出了更多的空间放置别的相关信息。 如图4.2所示,我的主界面也采用了TabWidget的分页栏,CPU、Memory和System三页中分别放置着有关CPU、内存和系统相关的信息。上方的两个按键分别可以实现杀死进程和搜索进程的功能。在最上方的About中还可以查看作者信息和退出该进程监视器。留出的一些空间用来显示CPU或内存相关的一些数据(如占有率、剩余内存、进程数等等)以及动态折线图,所有需要动态显示输出字样的地方都是采用Label实现的。图4.2主界面此外,使用Search按键进行进程搜索时,我使用了一个对话框的形式来展示所搜索进程的信息,这样可以使用户的关注点更加集中,如图4.3所示。图4.3使用对话框展示搜索的进程信息主要功能实现获取并显示主机名实现思路该功能实现起来很简单,主机名保存在/proc/self/root/etc/hostname文件中,只需要打开该文件并将字符串读出来,再用Label输出显示在System一页中即可。值得一提的是,整个程序中文件读取操作的方法都是首先定义一个Qfile类型的变量tempFile,使用tempFile.setFileName(file’sname)函数打开指定文件,再使用tempFile.readLine()函数将一行字符串读入一个Qstring变量中,最后使用tempFile.close()函数关闭文件。效果展示图4.4显示主机名源代码tempFile.setFileName("/proc/self/root/etc/hostname");if(!tempFile.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Cannotopenfilehostname!"),QMessageBox::Yes);return;}tempStr=tempFile.readLine();ui->label_Hostname->setText(tempStr); tempFile.close();显示系统当前时间、持续时间和启动时间实现思路Qt中提供的QDataTime类中直接包含有显示当前系统时间的函数currentDataTime(),使用"yyyy-MM-ddhh:mm:ss"的格式将其显示出来即可。 系统的持续时间存放在/proc/uptime文件中,该文件中存放着两个时间数字,第一个是系统运行的时间,第二个是系统休眠的时间,我们需要的是第一个时间。将这个时间读入一个Qstring中,由于带有小数,我们将其转化为double型进行处理。因为此时这个时间的单位是“秒”,我们需要使用辗转相除的方法逐步将其转化为“小时—分钟—秒”的格式,并将这些时间按照格式显示出来。 启动时间的算法是先得到上述的当前时间和持续时间,将这两个时间化为相同的格式(如“小时—分钟—秒”),两者之差即为系统的启动时间。此外,由于时间需要动态显示,这里使用了定时器进行实时更新,更新周期为1秒,代码如下:QTimer*timer=newQTimer(this);timer->setInterval(1000);connect(timer,SIGNAL(timeout()),SLOT(updatetime()));timer->start();效果展示图4.5显示时间源代码QFiletempFile;QStringtempStr;tempFile.setFileName("/proc/uptime");if(!tempFile.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Cannotopenfileuptime!"),QMessageBox::Yes);return;}tempStr=tempFile.readLine();QStringqtime_sec,qtime_hour,qtime_min;doubledtime;intntime,ntime_sec,ntime_hour,ntime_min,temp;qtime_sec=tempStr.section("",0,0);dtime=qtime_sec.toDouble();ntime=(int)dtime;ntime_hour=ntime/3600;temp=ntime-ntime_hour*3600;ntime_min=temp/60;temp=temp-ntime_min*60;ntime_sec=temp;qtime_hour=QString::number(ntime_hour);qtime_min=QString::number(ntime_min);qtime_sec=QString::number(ntime_sec);QDateTimecurtime=QDateTime::currentDateTime();QStringstr=curtime.toString("yyyy-MM-ddhh:mm:ss");ui->label_cur->setText(str);ui->label_Etime->setText(qtime_hour+"h"+qtime_min+"min"+qtime_sec+"sec");ui->label_Btime->setText("2016.3.1713:50:02");tempFile.close();显示系统的版本号实现思路如图4.6所示,/proc/version文件中保存着有关系统版本的信息。这里我们选择输出“Type”、“Version”和“Compiler”三个信息。首先通过index()函数找到“version”字符串的位置,将其之前的“Linux”字符串作为“Type”的输出。之后,继续使用index()函数找到“(”,这个位置和“version”之后的部分就是版本号的输出。最后,仍是使用index()函数找到“gccversion”字符串和“#”的位置,这之间的字符串就是编译器版本号的输出,这就完成了整个三项有关系统版本信息的输出。图4.6/proc/version文件内容效果展示图4.7显示系统版本源代码//打开操作系统信息文件tempFile.setFileName("/proc/version");if(!tempFile.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Cannotopenfileversion!"),QMessageBox::Yes);return;}tempStr=tempFile.readLine();pos=tempStr.indexOf("version");QString*os_version=newQString(tempStr.mid(0,pos-1));ui->label_SystemType->setText(*os_version);intpos1=tempStr.indexOf("(");QString*os_type=newQString(tempStr.mid(pos+8,pos1-pos-1));ui->label_SystemVersion->setText(*os_type);pos=tempStr.indexOf("gccversion");pos1=tempStr.indexOf("#");QString*gcc_info=newQString(tempStr.mid(pos+12,pos1-pos-14));ui->label_GCCVersion->setText(*gcc_info);tempFile.close();//关闭操作系统信息文件tempFile.setFileName("/proc/self/root/etc/hostname");if(!tempFile.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Cannotopenfilehostname!"),QMessageBox::Yes);return;}tempStr=tempFile.readLine();ui->label_Hostname->setText(tempStr);tempFile.close();}显示cpu的型号和主频大小实现思路这里我们需要输出CPU名称、类型和主频大小三个信息,这三个信息全部都在/proc/cpuinfo文件中,文件中这三个信息前面对应的项目名称分别为“modelname:”、“vendor_id:”和“cpuMHz”。通过使用index()函数找到这三个项目名,再将位置跳过这几个项目名的字符即可读入对应的信息。效果展示图4.8CPU信息注:由于电脑CPU的主频较为特殊,常态下为1.3GHz,但在高负荷下会采用boost技术提高主频,所以上下显示有差异。源代码staticintflag=0;tempFile.setFileName("/proc/cpuinfo");//打开CPU信息文件if(!tempFile.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Thecpuinfofilecannotopen!"),QMessageBox::Yes);return;}//循环读取文件内容,查找需要的信息while((flag!=3)){tempStr=tempFile.readLine();if(pos=tempStr.indexOf("modelname"),pos!=-1){pos+=12;//跳过前面的"modelname:"所占用的字符QString*cpu_name=newQString(tempStr.mid(pos,tempStr.length()-12));ui->label_CPUName->setText(*cpu_name);flag++;}elseif(pos=tempStr.indexOf("vendor_id"),pos!=-1){pos+=11;//跳过前面的"vendor_id:"所占用的字符QString*cpu_type=newQString(tempStr.mid(pos,tempStr.length()-11));ui->label_CPUType->setText(*cpu_type);flag++;}elseif(pos=tempStr.indexOf("cpuMHz"),pos!=-1){pos+=10;//跳过前面的"cpuMHz:"所占用的字符QString*cpu_frq=newQString(tempStr.mid(pos,tempStr.length()-10));doublecpufrq=cpu_frq->toDouble();cpu_frq->setNum(cpufrq);ui->label_CPUFrequency->setText(*cpu_frq+"MHz");flag++;}else//跳过其他的内容{//break;}}tempFile.close();//关闭CPU信息文件显示所有进程的信息实现思路我们使用两张ListWidget来展示所有进程的相关信息,这两张表分别放置在CPU和Memory两页中,CPU页中可以显示pid、进程名、父进程号、运行时间,而Memory页中可以显示pid、进程名、状态、优先级、使用内存大小。在/proc目录下有很多以数字命名的文件夹,每一个文件夹里实际上就是一个进程的所有信息,文件夹的名字就是该进程的pid。我们需要遍历这些文件夹,方法是使用以下两行代码将所有文件夹名读入一个字符串中,使用换行符作为间隔符:QStringListqsList=qd.entryList();QStringqs=qsList.join("\n");之后用index()函数逐一读取每个进程的pid,进入到对应的/proc/[pid]/stat文件中,这里保存着该进程的状态、优先级、父进程号、核心态下的使用时间、用户态下的使用时间这六项我们需要的信息,我们将这些信息读出来加以处理,就可以用以下的代码创建表中的一行信息,即某一个进程的相关信息(以CPU页为例):QListWidgetItem*item=newQListWidgetItem(id_of_pro+"\t"+proName+"\t"+proState+"\t"+proTime+"\t"+proppid,ui->cpulistWidget);而进程所占有的内存大小则是在/proc/[pid]/statm文件中,该文件中以空格为分隔符的第2项信息就是该进程所占有的内存大小,单位为KB,将它读出来并显示在Memory页中即可。效果展示图4.9Memory页进程信息(红线上方为信息项)图4.10CPU页进程信息源代码因两个分页的源代码较长且二者相似部分较多,这里只给出Memory页的源代码。QFiletempFile,tempFile_mem;QDirqd("/proc");QStringListqsList=qd.entryList();QStringqs=qsList.join("\n");QStringid_of_pro,tempStr;boolok;intfind_start=3;inta,b,pos;intnProPid;//进程PIDintnproMem;QStringproName;//进程名QStringproState;//进程状态QStringproPri;//进程优先级QStringproMem;//进程占用内存/*QListWidgetItem*title=newQListWidgetItem("PID\t"+"Name\t"+"\t"+"State\t"+"Priority\t"+"Usedmemory\t",ui->memlistWidget);*/QListWidgetItem*title=newQListWidgetItem("PID\t"+QString::fromUtf8("Name")+"\t\t"+QString::fromUtf8("State")+"\t"+QString::fromUtf8("Priority")+"\t"+QString::fromUtf8("Usedmemory"),ui->memlistWidget);//循环读取进程while(1){//获取进程PIDa=qs.indexOf("\n",find_start);b=qs.indexOf("\n",a+1);find_start=b;id_of_pro=qs.mid(a+1,b-a-1);nProPid=id_of_pro.toInt(&ok,10);if(!ok){break;}//打开PID所对应的进程状态文件tempFile.setFileName("/proc/"+id_of_pro+"/stat");if(!tempFile.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Cannotopenpidstat!"),QMessageBox::Yes);return;}tempStr=tempFile.readLine();if(tempStr.length()==0){break;}a=tempStr.indexOf("(");b=tempStr.indexOf(")");proName=tempStr.mid(a+1,b-a-1);proName.trimmed();//删除两端的空格proState=tempStr.section("",2,2);proPri=tempStr.section("",17,17);//proMem=tempStr.section("",22,22);tempFile_mem.setFileName("/proc/"+id_of_pro+"/statm");//process'smemoryinfoif(!tempFile_mem.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Cannotopenpidstatm!"),QMessageBox::Yes);return;}tempStr=tempFile_mem.readLine();if(tempStr.length()==0){break;}proMem=tempStr.section("",1,1);nproMem=proMem.toInt();if(nproMem<0)nproMem=-nproMem;nproMem=nproMem*4;proMem=QString::number(nproMem,10);tempFile_mem.close();if(proName.length()>=11){QListWidgetItem*item=newQListWidgetItem(id_of_pro+"\t"+proName+"\t"+proState+"\t"+proPri+"\t"+proMem+"KB",ui->memlistWidget);}else{QListWidgetItem*item=newQListWidgetItem(id_of_pro+"\t"+proName+"\t\t"+proState+"\t"+proPri+"\t"+proMem+"KB",ui->memlistWidget);}}tempFile.close();//关闭该PID进程的状态文件通过pid或进程名查询或杀死进程实现思路对于查询和删除进程这两个功能,使用pid来完成是最简单的,但却不太符合常规用户的使用习惯,使用进程名显然更加方便。所以我使用了一个checkbox来选择是使用pid还是进程名来查询或者杀死进程,如图4.11所示。如果用户误将两者都打勾,则会提示“illegallycheck”的字样。图4.11使用checkbox实现两种查询或杀死进程的方法如果选择了使用pid来实现功能,则将这个pid与/proc文件夹中的所有pid进行比对,如果相同,则进入到该文件夹中利用4.3.5中的方法来获取相关的信息,并通过另一个对话框显示出来。如果要杀死该进程,只需使用以下语句即可,其中prokill为输入的pid:system("kill"+prokill.toLatin1());如果选择使用进程名来实现功能,则需要使用类似4.3.5中的方法将这个进程名与每一个/proc/[pid]/stat中的进程名比对,找到了匹配的结果后,将这个进程的pid记录下来,然后就转化为了使用pid查询或杀死进程的方法了。效果展示使用pid来杀死firefox进程,其pid=5308:图4.12使用pid杀死firefox进程前 使用pid杀死后,显示“Success”,可以看到左边的Firefox已关闭;图4.13使用pid杀死firefox进程后使用进程名杀死firefox进程:图4.14使用进程名杀死firefox进程使用pid查询firefox进程,pid=5442;图4.15使用pid查询firefox进程使用进程名查询firefox进程,二者结果相同;图4.16使用进程名查询firefox进程当checkbox重复选中时,提示错误。图4.17重复选中时的错误提示源代码杀死进程:QStringprokill=ui->killlineEdit->text().trimmed();if(ui->checkBox_pid->isChecked()&&!(ui->checkBox_name->isChecked())){system("kill"+prokill.toLatin1());QMessageBox::warning(this,tr("ok"),QString::fromUtf8("Success!"),QMessageBox::Yes);ui->killlineEdit->clear();}if(!(ui->checkBox_pid->isChecked()^ui->checkBox_name->isChecked())){QMessageBox::warning(this,tr("warning"),QString::fromUtf8("Illegalcheck!"),QMessageBox::Yes);}if(!ui->checkBox_pid->isChecked()&&(ui->checkBox_name->isChecked())){QStringproName;inta,b;intfind_start=3;intnProPid;boolok;QFiletempFile;QDirqd("/proc");QStringListqsList=qd.entryList();QStringqs=qsList.join("\n");QStringid_of_pro,tempStr;while(proName!=prokill){a=qs.indexOf("\n",find_start);b=qs.indexOf("\n",a+1);find_start=b;id_of_pro=qs.mid(a+1,b-a-1);nProPid=id_of_pro.toInt(&ok,10);if(!ok){QMessageBox::warning(this,tr("warning"),QString::fromUtf8("Cannotfindit!"),QMessageBox::Yes);break;}//打开PID所对应的进程状态文件tempFile.setFileName("/proc/"+id_of_pro+"/stat");if(!tempFile.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Cannotopenpidstat!"),QMessageBox::Yes);return;}tempStr=tempFile.readLine();if(tempStr.length()==0){break;}a=tempStr.indexOf("(");b=tempStr.indexOf(")");proName=tempStr.mid(a+1,b-a-1);tempFile.close();}system("kill"+id_of_pro.toLatin1());QMessageBox::warning(this,tr("ok"),QString::fromUtf8("Success!"),QMessageBox::Yes);ui->killlineEdit->clear();}查询进程voidMainWindow::on_srchBtn_clicked(){//QStringprosrch=ui->srchlineEdit->text.trimmed();if(ui->checkBox_pid->isChecked()&&!(ui->checkBox_name->isChecked())){QStringid_of_pro=ui->srchlineEdit->text().trimmed();info.get_pid(id_of_pro);info.exec();ui->srchlineEdit->clear();}if(!(ui->checkBox_pid->isChecked()^ui->checkBox_name->isChecked())){QMessageBox::warning(this,tr("warning"),QString::fromUtf8("Illegalcheck!"),QMessageBox::Yes);}if(!ui->checkBox_pid->isChecked()&&(ui->checkBox_name->isChecked())){QStringprosrch=ui->srchlineEdit->text().trimmed();QStringproName;inta,b;intfind_start=3;intnProPid;boolok;QFiletempFile;QDirqd("/proc");QStringListqsList=qd.entryList();QStringqs=qsList.join("\n");QStringid_of_pro,tempStr;while(proName!=prosrch){a=qs.indexOf("\n",find_start);b=qs.indexOf("\n",a+1);find_start=b;id_of_pro=qs.mid(a+1,b-a-1);nProPid=id_of_pro.toInt(&ok,10);if(!ok){QMessageBox::warning(this,tr("warning"),QString::fromUtf8("Cannotfindit!"),QMessageBox::Yes);break;}//打开PID所对应的进程状态文件tempFile.setFileName("/proc/"+id_of_pro+"/stat");if(!tempFile.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Cannotopenpidstat!"),QMessageBox::Yes);return;}tempStr=tempFile.readLine();if(tempStr.length()==0){break;}a=tempStr.indexOf("(");b=tempStr.indexOf(")");proName=tempStr.mid(a+1,b-a-1);tempFile.close();}info.get_pid(id_of_pro);info.exec();ui->srchlineEdit->clear();}}voidinfoDlg::get_pid(QStringpid){QStringid_of_pro=pid;QFiletempFile;QStringtempStr;QDirqd("/proc");QStringListqsList=qd.entryList();QStringqs=qsList.join("\n");boolok;inta,b;intnProPid;//进程PIDintnproMem;QStringproName;//进程名QStringproState;//进程状态QStringproPri;//进程优先级QStringproMem;//进程占用内存QStringproTime1,proTime2,proTime;QStringproppid;//获取进程PIDnProPid=id_of_pro.toInt(&ok,10);//打开PID所对应的进程状态文件tempFile.setFileName("/proc/"+id_of_pro+"/stat");if(!tempFile.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Cannotopenpidstat!"),QMessageBox::Yes);return;}tempStr=tempFile.readLine();a=tempStr.indexOf("(");b=tempStr.indexOf(")");proName=tempStr.mid(a+1,b-a-1);proName.trimmed();//删除两端的空格proState=tempStr.section("",2,2);proPri=tempStr.section("",17,17);//proMem=tempStr.section("",22,22);proppid=tempStr.section("",3,3);proTime1=tempStr.section("",12,12);proTime2=tempStr.section("",13,13);intntime1=proTime1.toInt();intntime2=proTime2.toInt();intntime=ntime1+ntime2;proTime=QString::number(ntime);tempFile.close();tempFile.setFileName("/proc/"+id_of_pro+"/statm");//process'smemoryinfoif(!tempFile.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Cannotopenpidstatm!"),QMessageBox::Yes);return;}tempStr=tempFile.readLine();proMem=tempStr.section("",1,1);nproMem=proMem.toInt();if(nproMem<0)nproMem=-nproMem;nproMem=nproMem*4;proMem=QString::number(nproMem,10);tempFile.close();ui->label_name->setText(proName);ui->label_ppid->setText(proppid);ui->label_priority->setText(proPri);ui->label_mem->setText(proMem+"KB");ui->label_state->setText(proState);ui->label_time->setText(proTime);}显示当前内存和交换分区使用情况实现思路这部分同样需要计时器实时更新。如图4.18所示,在/proc/meminfo文件中,每一个信息项前面都已经表明了这个信息项的名称,所以我们只需要使用index()函数对这些名称进行检索、定位后选取后面的数字作为需要的信息即可。之后将这些信息进行转换为int型,再进行一些运算,如对于可直接读出的总内存和空闲内存,两者相减得到的是已使用内存,用已使用内存比上总内存即是内存的使用率。图4.18meminfo内容效果展示图4.19内存和交换分区使用情况源代码tempFile.setFileName("/proc/meminfo");//打开内存信息文件if(!tempFile.open(QIODevice::ReadOnly)){QMessageBox::warning(this,tr("warning"),tr("Cannotopenmeminfo!"),QMessageBox::Yes);return;}QStringmemTotal;QStringmemFree;QStringmemUsed;QStringmemRate;QStringswapTotal;QStringswapFree;QStringswapUsed;QStringswapRate;intnMemTotal,nMemFree,nMemUsed,nMemrate,nSwapTotal,nSwapFree,nSwapUsed,nSwapRate;while(1){tempStr=tempFile.readLine();pos=tempStr.indexOf("MemTotal");if(pos!=-1){memTotal=tempStr.mid(pos+10,tempStr.length()-13);memTotal=memTotal.trimmed();nMemTotal=memTotal.toInt()/1024;}elseif(pos=tempStr.indexOf("MemFree"),pos!=-1){memFree=tempStr.mid(pos+9,tempStr.length()-12);memFree=memFree.trimmed();nMemFree=memFree.toInt()/1024;}elseif(pos=tempStr.indexOf("SwapTotal"),pos!=-1){swapTotal=tempStr.mid(pos+11,tempStr.length()-14);swapTotal=swapTotal.trimmed();nSwapTotal=swapTotal.toInt()/1024;}elseif(pos=tempStr.indexOf("SwapFree"),pos!=-1){swapFree=tempStr.mid(pos+10,tempStr.length()-13);swapFree=swapFree.trimmed();nSwapFree=swapFree.toInt()/1024;break;}}nMemUsed=nMemTotal-nMemFree;nSwapUsed=nSwapTotal-nSwapFree;nMemrate=nMemUsed*100/nMemTotal;nSwapRate=nSwapUsed*100/nSwapTotal;memUsed=QString::number(nMemUsed,10);memFree=QString::number(nMemFree,10);memTotal=QString::number(nMemTotal,10);memRate=QString::number(nMemrate,10);swapUsed=QString::number(nSwapUsed,10);swapFree=QString::number(nSwapFree,10);swapTotal=QString::number(nSwapTotal,10);swapRate=QString::number(nSwapRate,10);ui->label_RAM_Used->setText(memUsed+"MB");ui->label_RAM_Left->se
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 《长方形和正方形的周长-认识长方形和正方形》说课稿-2024-2025学年三年级上册数学北京版
- 《第二单元 数字画家 6 形状与填充》说课稿-2024-2025学年浙江摄影版(三起)(2020)信息技术三年级上册
- 2024年五年级英语下册 Unit 8 Brithday第5课时说课稿 译林牛津版
- 《第2课 电话家族 3 学会打电话》(说课稿)-2023-2024学年五年级下册综合实践活动安徽大学版
- 《分数的初步认识(一)》(说课稿)-2024-2025学年苏教版数学三年级上册
- 《劳动创造幸福》(说课稿)皖教版三年级下册综合实践活动
- 2《不一样的你我他》第一课时(说课稿)统编版道德与法治三年级下册
- 中央2025年中国外文出版发行事业局所属企事业单位招聘23人笔试历年参考题库附带答案详解
- 2025年度国际物流运输及供应链管理合作协议
- 2025年度股东股份协议书:跨境电商平台股份分配与运营管理协议
- 长江委水文局2025年校园招聘17人历年高频重点提升(共500题)附带答案详解
- 2025年湖南韶山干部学院公开招聘15人历年高频重点提升(共500题)附带答案详解
- 广东省广州市番禺区2023-2024学年七年级上学期期末数学试题
- 智研咨询发布:2024年中国MVR蒸汽机械行业市场全景调查及投资前景预测报告
- JGJ46-2024 建筑与市政工程施工现场临时用电安全技术标准
- 家谱、宗谱颁谱庆典讲话
- 方案报审表(样表)
- pp顾问的常见面试问题
- 法理学原理与案例完整版教学课件全套ppt教程
- 隧道仰拱施工之仰拱栈桥结构计算书
- 软体家具、沙发质量检验及工艺
评论
0/150
提交评论