第一篇:操作系統課設任務
一、操作系統課程設計要求:
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.tmdps.cntl.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、在上機實現該程序之后,要求寫出實驗報告,其中包括實驗名稱、實驗目的、實驗內容、程序的主要流程圖、實驗心得和主要源程序清單等。第五篇:操作系統本科實驗任務