第一篇:操作系統(tǒng)課設(shè)
操作系統(tǒng)課程設(shè)計
一實驗?zāi)康?/p>
在多道程序或多任務(wù)系統(tǒng)中,系統(tǒng)中同時處于就緒態(tài)的進程有若干個,也就是說能運行的進程數(shù)遠遠大于處理機個數(shù)。為了使系統(tǒng)中的各進程能有條不紊地進行,必須選擇某種調(diào)度策略,以選擇一進程占用處理機。要求學(xué)生設(shè)計一個模擬單處理機調(diào)度的算法,以加深對處理機調(diào)度的概念理解。
通過自己變成來實現(xiàn)頁面調(diào)度算法,進一步理解頁面調(diào)度算法 的概念及含義,提高對頁面調(diào)度算法的認識,同時提高自己的動手實踐能力。加深我們對主存與輔助存儲器統(tǒng)一管理、邏輯地址與物理地址轉(zhuǎn)換、部分裝入和部分替換問題的理解,同時,有利于我們對虛擬存儲技術(shù)的理解。
為了了解系統(tǒng)的資源分配情況,假定系統(tǒng)的任何一種資源在 任一時刻只能被一個進程使用。任何進程已經(jīng)占用的資源只能由進程自己釋放,而不能由其他進程搶占。當進程申請的資源不能滿足時,必須等待。因此,只要資源分配算法能保證進程的資源請求,且不出現(xiàn)循環(huán)等待,則系統(tǒng)不會出現(xiàn)死鎖。
編寫模擬系統(tǒng)進行資源調(diào)度的程序,一個是隨機算法,即只 要系統(tǒng)剩余資源能滿足進程的當前請求,就立即將資源分配給進程,以觀察死鎖產(chǎn)生情況;一個是采用銀行家算法,有效地避免死鎖的產(chǎn)生。
模擬進程的資源分配算法,了解死鎖的產(chǎn)生和避免的辦法。通過設(shè)計一個磁盤調(diào)度模擬系統(tǒng),深入理解磁盤的工作原理,從而使磁盤調(diào)度更加形象化,容易使人理解,使磁盤調(diào)度的特點更簡單明了,能使使用者加深對磁盤調(diào)度算法的理解。具體實現(xiàn)為,運用一門高級編程語言編寫程序模擬磁盤調(diào)度的過程,采用先來先服務(wù)算法和電梯算法,模擬并輸出存取臂的移動順序,并計算存取臂移動的磁道總數(shù)。能夠處理以下的情形:
(1)可根據(jù)需要輸入當前磁頭的位置,磁頭移動方向;(2)能夠輸入柱面數(shù),磁道訪問序列等參數(shù),并能夠顯示調(diào)度結(jié)果(磁盤訪問請求的磁道號以及磁頭移動的總磁道數(shù))。
二、實驗內(nèi)容
利用C++實驗以下算法: 處理機管理中:
(1)先來先服務(wù)算法(FCFS)
實驗題目:
<1>假設(shè)系統(tǒng)中有3~5個進程,每個進程由一個進程控制塊(PCB)來標識。
<2>設(shè)置一個隊首指針head,用來指出最先進入系統(tǒng)的進程,各就緒進程通過鏈接指針連在一起。
<3>處理機調(diào)度時總是選擇隊首指針指向的進程投入運行。由于本實驗是模擬實驗,所以對被選中進程并不實際啟動運行,而只是執(zhí)行。估計運行時間減1,用這個操作來模擬進程的一次運行,而且省去進程的現(xiàn)場保護和現(xiàn)場恢復(fù)工作。
<4>在所設(shè)計的程序中應(yīng)有顯示或打印語句,能顯示或打印正運行的進程名字、已運行時間、還剩時間、就緒對列中進程名字等。所有進程運行完成時,給出各進程的周轉(zhuǎn)時間和平均周轉(zhuǎn)時間.數(shù)據(jù)結(jié)構(gòu)設(shè)計如下:
struct PCB
//定義進程控制塊
{
char ID[3];
//進程號
char name[10];
//進程名
char state;
//運行狀態(tài)
int arrivetime;//到達時間
int starttime;//進程開始時間
int finishtime;//進程結(jié)束時間
int servicetime;
//運行時間
float turnaroundtime;//周轉(zhuǎn)時間
float weightedturnaroundtime;//帶權(quán)周轉(zhuǎn)時間
struct PCB *next;//指向下個進程
};
(2)時間片輪算法
實驗題目:
<1>假設(shè)系統(tǒng)中有3~5個進程,每個進程由一個進程控制塊(PCB)來代表。
<2>按照進程到達的先后順序排成一個循環(huán)隊列,設(shè)一個隊首指針指向第一個到達的進程的首址。另外再設(shè)一個當前運行進程指針,指向當前正運行的進程。
<3>執(zhí)行處理機調(diào)度時,首先選擇隊首的第一個進程運行。<4>由于本實驗是模擬實驗,所以對被選中進程并不實際啟動運行,而只是執(zhí)行:
估計運行時間減1 用這個操作來模擬進程的一次運行。
<5>進程運行一次后,以后的調(diào)度則將當前指針依次下移一個位置,指向下一個進程,即調(diào)整當前運行指針指向該進程的鏈接指針所指進程,以指示應(yīng)運行進程,同時
還應(yīng)判斷該進程的剩余運行時間是否為0.若不為0,則等待下一輪的運行,若該進程的剩余運行時間為0,則將該進程的狀態(tài)置為完成狀態(tài)“C”,并退出循環(huán)隊列。<6>若就緒隊列不空,則重復(fù)上述的步驟(4)和(5)直到所有進程都運行完為止。
<7>在所設(shè)計的調(diào)度程序中,應(yīng)包含顯示或打印語句吧,已便顯示或打印每次選中進程的名稱及運行一次后隊列的變化情況。數(shù)據(jù)結(jié)構(gòu)設(shè)計如下:
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();
函數(shù)
int readydata();
int runprocess();
進程的函數(shù)
int readyprocess();
static char R='r',C='c';
量
unsigned long current;
//到達時間
//進程狀態(tài) //鏈接指針
//就緒隊列頭指針 //運行隊列頭指針
//判斷是否有就緒進程的 //運行進程的函數(shù)
//檢查就緒隊列并準備運行
//聲明一個文件指針
//記錄系統(tǒng)當前時間的變
//建立進程的函數(shù)
(3)優(yōu)先級調(diào)度算法
實驗題目:
<1>假設(shè)系統(tǒng)中有3~5個進程,每個進程由一個進程控制塊(PCB)來代表。進程的優(yōu)先數(shù)、要求運行時間和估計運行
時間由用戶程序任意設(shè)計,且優(yōu)先數(shù)越低,優(yōu)先級越高。調(diào)度時,總是選擇優(yōu)先級最高的進程運行。
<2>為了調(diào)度方便,設(shè)計一個指針指向就緒隊列的第一個進程。另外再設(shè)一個當前運行進程指針,指向當前正運行的進程。
<3>處理機調(diào)度時,總是選擇已經(jīng)到達隊列的優(yōu)先級最高的進程運行。為了采用 動態(tài)優(yōu)先級調(diào)度,進程每運行一次,其優(yōu)先級就減1。由于本實驗是模擬實驗,所以對被選中進程并不實際啟動運行,而只是執(zhí)行:
優(yōu)先數(shù)加1和估計運行時間減1 用這個操作來模擬進程的一次運行。
<4>進程運行一次后,若剩余的運行時間不為0,且其優(yōu)先級低于就緒隊列的其他進程的優(yōu)先級,則選擇一個高優(yōu)先級進程搶占CPU;若剩余運行時間為0,則把它的狀態(tài)改為完成狀態(tài)“C”,并撤出就緒隊列。
<5>若就緒隊列不空,則重復(fù)上述的步驟(3)和(4)直到所有進程都運行完為止。
<6>在所設(shè)計的程序中應(yīng)有顯示或打印語句,以顯示或打印每次被選中進程的進程名字、運行一次后進程的變化以及就緒隊列中的各進程排隊情況等。數(shù)據(jù)結(jié)構(gòu)設(shè)計如下:
struct pcb {
/* 定義進程控制塊PCB */
char name[10];
//進程名
char state;
//進程狀態(tài)
int super;
//優(yōu)先級數(shù)
int ntime;
//需要運行時間
int rtime;
//已運行時間 頁面替換算法中:
(1)先進先出頁面替換算法(FIFO)(2)最近最少使用頁面替換算法(LRU)(3)最少使用頻率頁面替換算法(LFU)
數(shù)據(jù)結(jié)構(gòu)設(shè)計如下:
struct PageFrame
//頁框結(jié)構(gòu) {
int id;
//頁框號
int pageId;
//駐留的頁號
int visitedCount;//駐留頁計數(shù)器,訪問加1 int unvisitedCount;//最近訪問,訪問清零,未訪問加1 bool replace;//將被淘汰為true int stayTime;
//駐留時間計數(shù) int nextsite;};銀行家算法 實驗題目
<1>
為了觀察死鎖產(chǎn)生和避免的情況,要求設(shè)計3~4個并發(fā)進程,共享系統(tǒng)的10個同類補課搶占的資源。各進程是動態(tài)進行資源的申請和釋放。
<2>
用隨機算法和銀行家算法分別設(shè)計一個資源分配程序,運行這兩個程序,觀察系統(tǒng)運行情況,并對系統(tǒng)運行的每一步情況進行顯示。
程序中使用的數(shù)據(jù)結(jié)構(gòu)及主要符號說明
初始化這組進程的最大資源請求和依次申請的資源序列,把進程已占用和需求的資源情況記錄在進程控制塊中,假定進程控制塊的格式如下圖所示;
進程狀態(tài)有:就緒、等待和完成。當系統(tǒng)不能滿足進程的資源請求時,進程處于等待態(tài)。
“資源需求總量”表示進程運行過程中對資源的最大需求量。顯然每個進程的資源需求總量不應(yīng)超過系統(tǒng)擁有的資源總量?!耙颜假Y源量”表示進程目前已經(jīng)得到但還未歸還的資源量。因此,進程在以后還需要的剩余資源量等于資源需要總量減去已占資源量。“當前申請量”指進程都拿過去按運行時需要申請的資源量。銀行家算法分配資源的原則是:
(1)當某個進程提出資源請求時,假定先分配給它,之后調(diào)用系統(tǒng)安全性檢查算法,進行系統(tǒng)安全性檢查,若系統(tǒng)安全,須分配變?yōu)檎娣峙?。否則作廢假分配,讓進程等待。(2)系統(tǒng)安全性檢查算法。驅(qū)動調(diào)度算法中:
作為操作系統(tǒng)的輔助存儲器,用來存放文件的磁盤是一類高速大容量旋轉(zhuǎn)型存儲設(shè)備,在繁重的I/O負載下,同時會有若干傳輸請求來到并等待處理,系統(tǒng)必須采用一種調(diào)度策略,按照最佳次序執(zhí)行要求訪問的諸多請求,減少為若干I/O請求服務(wù)所需消耗的總時間。
磁盤驅(qū)動調(diào)度對磁盤的效率有重要影響。磁盤驅(qū)動調(diào)度算法的好壞直接影響輔助存儲器的效率,從而影響計算機系統(tǒng)的整體效率。(1)電梯調(diào)度算法(2)最短查找時間優(yōu)先算法(3)先來先服務(wù)算法
三、實驗心得
通過本次課程設(shè)計,我認識到要將操作系統(tǒng)這門計算機專業(yè)課學(xué)好不易——不僅僅是要把書上的基本知識學(xué)好,而且還要不斷進行實踐,將所學(xué)與實踐操作結(jié)合起來才能更好地鞏固所學(xué),才能提高自己實踐能力。在以后的學(xué)習(xí)中一方面我要不斷的鞏固自己所學(xué)的理論知識,一方面還要多參加實際操作工作以便提高自己的實際操作能力。
第二篇:操作系統(tǒng)課設(shè)
課 程 設(shè) 計 報 告
課程名稱: 計算機操作系統(tǒng)
專業(yè)班級:
學(xué) 號: 姓 名: 指導(dǎo)教師: 報告日期:
計算機科學(xué)與技術(shù)學(xué)院
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
目 錄 2 3 實驗?zāi)康?.............................................................................................2 實驗環(huán)境..............................................................................................2 實驗內(nèi)容..............................................................................................2 3.1 3.2 3.3 3.4 3.5 4 實驗一...............................................................................................2 實驗二...............................................................................................2 實驗三...............................................................................................2 實驗四(選做)................................................................................3 實驗五(選做)................................................................................3
設(shè)計與實現(xiàn)...........................................................................................3 4.1 4.2 4.3 4.4 實驗一...............................................................................................3 實驗二.............................................................................................10 實驗三.............................................................................................14 實驗四.............................................................................................20 心得體會............................................................................................43
I
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告 ·掌握Linux操作系統(tǒng)的使用方法; ·了解Linux系統(tǒng)內(nèi)核代碼結(jié)構(gòu); ·掌握實例操作系統(tǒng)的實現(xiàn)方法;
實驗?zāi)康?實驗環(huán)境
本次課程設(shè)計采用的操作系統(tǒng)環(huán)境是windows8、Ubuntu雙系統(tǒng),Ubuntu系統(tǒng)版本號為14.04,內(nèi)核版本號為linux 3.13.0;采用的編程環(huán)境為CodeBlocks IDE和QtCreator。3.1 實驗一
實驗內(nèi)容
掌握Linux操作系統(tǒng)的使用方法,包括鍵盤命令、系統(tǒng)調(diào)用;掌握在Linux下的編程環(huán)境。
(1)編寫一個C程序,其內(nèi)容為實現(xiàn)文件拷貝的功能。
(2)編寫一個C程序,其內(nèi)容為分窗口同時顯示三個并發(fā)進程的運行結(jié)果。要求用到Linux下的圖形庫(GTK/Qt)。
3.2 實驗二
掌握系統(tǒng)調(diào)用的實現(xiàn)過程,通過編譯內(nèi)核方法,增加一個新的系統(tǒng)調(diào)用,另編寫一個應(yīng)用程序,調(diào)用新增加的系統(tǒng)調(diào)用。實現(xiàn)的功能是:文件拷貝。
3.3 實驗三
掌握增加設(shè)備驅(qū)動程序的方法。通過模塊方法,增加一個新的設(shè)備驅(qū)動程序,其功能可以簡單。(實現(xiàn)字符設(shè)備的驅(qū)動)
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
3.4 實驗四(選做)
了解和掌握/proc文件系統(tǒng)的特點和使用方法(1)了解/proc文件的特點和使用方法;
(2)監(jiān)控系統(tǒng)狀態(tài),顯示系統(tǒng)中若干部件使用狀態(tài);(3)用圖形界面實現(xiàn)系統(tǒng)監(jiān)控狀態(tài);
3.5 實驗五(選做)
設(shè)計并實現(xiàn)一個模擬的文件系統(tǒng)。
多用戶的多級目錄的文件系統(tǒng)設(shè)計。多用戶、多級目錄、login(用戶登錄)、系統(tǒng)初始化(建文件卷,提供登錄模塊)、文件的創(chuàng)建、文件的打開、文件的讀寫、文件關(guān)閉、刪除文件、創(chuàng)建目錄(建立子目錄)、改變當前目錄、列出文件目錄、退出。4.1 實驗一
4.1.1 實驗要求
設(shè)計與實現(xiàn)
掌握Linux操作系統(tǒng)的使用方法,包括鍵盤命令、系統(tǒng)調(diào)用;掌握在Linux下的編程環(huán)境。4.1.2 具體實現(xiàn)
本實驗內(nèi)容是用CodeBlocks IDE實現(xiàn)的,該軟件整合了函數(shù)庫和編譯器,因此使用起來非常方便。
(1)編寫一個C程序,其內(nèi)容為實現(xiàn)文件拷貝的功能。
在windows操作系統(tǒng)上實現(xiàn)的文件拷貝功能一般使用fopen、fread、fwrite三個來自標準C函數(shù)庫的函數(shù)執(zhí)行對文件的打開、讀、寫操作,而本次實驗要求使用Linux系統(tǒng)的系統(tǒng)調(diào)用open、read、write實現(xiàn)上述三個操作。
用到的主要頭文件如下:
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
stdio.h——標準輸入輸出頭文件 string.h——字符串處理相關(guān)頭文件
unistd.h——Linux系統(tǒng)調(diào)用頭文件,比如read、write fcntl.h——包含open系統(tǒng)調(diào)用
errno.h——包含一些調(diào)試錯誤時用到的變量 具體實現(xiàn)思路:
打開兩個文件(分別是源文件和目標文件,可以是任意字符流形式存儲的文件,包括文本文件、照片等),調(diào)用read函數(shù)讀取源文件的內(nèi)容,將read的返回值作為while循環(huán)的判斷條件,當返回值大于0(即還未讀取完畢源文件中的內(nèi)容)時,調(diào)用write執(zhí)行向目標文件寫的操作,否則跳出循環(huán),表示源文件已經(jīng)被拷貝到目標文件,然后調(diào)用close關(guān)閉源文件和目標文件。
代碼編寫完成后,在CodeBlocks上編譯運行即可。程序運行之前,桌面上只有“教程.docx”,運行之后,桌面上新建了“教程副本.docx”,并且“教程.docx”中的內(nèi)容被復(fù)制到了“教程副本.docx”,程序運行結(jié)果如下所示:
詳細代碼見4.1.3。
(2)編寫一個C程序,其內(nèi)容為分窗口同時顯示三個并發(fā)進程的運行結(jié)果。要求用到Linux下的圖形庫(GTK/Qt)。
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
本次實驗使用的圖形庫是跨平臺的開發(fā)工具Qt。首先下載Qt的安裝包并安裝。Qt安裝完之后,先新建一個Qt控制臺應(yīng)用MAIN作為主進程,用于調(diào)用三個并發(fā)的子進程。在主進程的main函數(shù)中,使用fork創(chuàng)建三個子進程,若進程創(chuàng)建成功(即fork函數(shù)返回值等于0),則使用execv函數(shù)進入對應(yīng)的子進程(get、copy、put)。主進程程序編寫完成后,再新建三個Qt Widgets Application,分別作為三個子進程get、copy、put(所實現(xiàn)的功能并不是拷貝)。由于三個子進程窗口顯示的內(nèi)容形式一模一樣,所以以子進程get為例。get進程的窗口顯示了一下四個內(nèi)容:當前時間、子進程名稱、子進程的pid和父進程MAIN的pid。用Qt的對象QDateTime獲取系統(tǒng)當前時間,然后將時間轉(zhuǎn)換成一個字符串寫在一個QLabel類的實例中,然后將該實例添加至窗口;直接把當前進程名稱寫在一個標簽上然后添加至窗口;使用getpid和getppid函數(shù)分別獲取當前進程號和父進程號,然后調(diào)用sprintf把進程號轉(zhuǎn)換成字符串類型之后寫在標簽上并添加至窗口即可。
主進程和三個子進程的程序全部編寫完后,直接在Qt上編譯運行。程序運行結(jié)果如下所示:
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
詳細代碼見4.1.3。
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
4.1.3 源代碼(1)文件拷貝源代碼
#include
#define SIZE 10
///每次讀取的字符數(shù)目
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)三個并發(fā)進程
#主進程MAIN #include
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
{
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()));
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
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”
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
#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 實驗要求
掌握系統(tǒng)調(diào)用的實現(xiàn)過程,通過編譯內(nèi)核方法,增加一個新的系統(tǒng)調(diào)用,另編寫一個應(yīng)用程序,調(diào)用新增加的系統(tǒng)調(diào)用。4.2.2 具體實現(xiàn)(1)系統(tǒng)調(diào)用的原理
用戶進程不能訪問內(nèi)核所占內(nèi)存空間,也不能調(diào)用內(nèi)核函數(shù)。進程調(diào)用一個特殊的指令,這個指令會跳到一個事先定義的內(nèi)核中的一個位置。在Intel CPU中,由中斷INT 0x80實現(xiàn)。(與DOS功能調(diào)用int0x21很相似)跳轉(zhuǎn)到的內(nèi)核位置叫做sysem_call。檢查系統(tǒng)調(diào)用號,這個號碼代表進程請求哪種服務(wù)。然后,它查看系統(tǒng)
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
調(diào)用表(sys_call_table)找到所調(diào)用的內(nèi)核函數(shù)入口地址。接著,就調(diào)用函數(shù),等返回后,做一些系統(tǒng)檢查,最后返回到進程(如果這個進程時間用盡,就返回到其他進程)。
(2)編寫新的系統(tǒng)調(diào)用程序
新的系統(tǒng)調(diào)用程序?qū)崿F(xiàn)的功能是:將一個文件中的內(nèi)容拷貝到另一個文件中。這個系統(tǒng)調(diào)用的參數(shù)是兩個char*型的字符指針SourceFile、GoalFile,分別表示源文件和目標文件的路徑名。用戶進程中的open、read、write、close函數(shù)此時對應(yīng)內(nèi)核函數(shù) sys_open、sys_read、sys_write、sys_close函數(shù)。循環(huán)拷貝的判斷條件還是
sys_read的返回值,當其大于0的時候執(zhí)行循環(huán),否則表示源文件已拷貝到了目標文件。
mm_segment_t類型的變量fs的作用是在讀寫文件前得到當前fs,避免使用的緩沖區(qū)超過了用戶空間的地址范圍而報錯。
詳細代碼見4.2.3。(3)編譯內(nèi)核 ①下載并解壓內(nèi)核
先到Linux官方網(wǎng)站http://004km.cntl.h> #define BUFFER_SIZE 102400 int main(void){ int dev,i=0;char c;
char source[BUFFER_SIZE];//寫入MyDeviceDriver設(shè)備的內(nèi)容
char goal[BUFFER_SIZE];//MyDeviceDriver設(shè)備的內(nèi)容讀入到該goal中
printf(“input the string you want to write in your device:n”);while((c=getchar())!='n')
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
{
source[i++]=c;} printf(“n”);
if((dev=open(“/dev/MyDeviceDriver”,O_RDWR))==-1)//打開MyDeviceDriver設(shè)備失敗
printf(“FAIL to open MyDeviceDriver!n”);else//成功
printf(“SUCCESS to open MyDeviceDriver!n”);
printf(“source:n%snn”,source);
write(dev,source,sizeof(source));//把source中的內(nèi)容寫入MyDeviceDriver設(shè)備
lseek(dev,0,SEEK_SET);//把文件指針定位到文件開始的位置
read(dev,goal,sizeof(source));//把MyDeviceDriver設(shè)備中的內(nèi)容讀入到goal中
printf(“goal:n%snn”,goal);
return 0;} 4.4 實驗四
實驗四有兩個選做題目,分別是proc文件監(jiān)控系統(tǒng)和小型文件系統(tǒng),本次實驗我選擇的題目是proc文件監(jiān)控系統(tǒng)。4.4.1 實驗要求
了解/proc文件的特點和使用方法;監(jiān)控系統(tǒng)狀態(tài),顯示系統(tǒng)中若干部件使用狀態(tài);用圖形界面實現(xiàn)系統(tǒng)監(jiān)控狀態(tài)。4.4.2 具體實現(xiàn)
(1)/proc文件系統(tǒng)的特點
Linux的PROC文件系統(tǒng)是進程文件系統(tǒng)和內(nèi)核文件系統(tǒng)的組成的復(fù)合體,是將內(nèi)核數(shù)據(jù)對象化為文件形式進行存取的一種內(nèi)存文件系統(tǒng),是監(jiān)控內(nèi)核的一種用戶接口。它擁有一些特殊的文件(純文本),從中可以獲取系統(tǒng)狀態(tài)信息。(2)功能清單
①獲取并顯示主機名,與之相關(guān)的proc文件為/proc/sys/kernel/hostname; ②獲取并顯示系統(tǒng)啟動的時間,與之相關(guān)的proc文件為/proc/uptime; ③顯示系統(tǒng)到目前為止持續(xù)運行的時間,與之相關(guān)的proc文件為/proc/uptime; ④顯示系統(tǒng)的版本號,與之相關(guān)的proc文件為/proc/sys/kernel/ostype和/proc/sys/kernel/osrelease;
⑤ 顯示CPU的型號和主頻大小,與之相關(guān)的proc文件為/proc/cpuinfo;
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
⑥通過pid或者進程名查詢一個進程,并顯示該進程的詳細信息,提供殺掉該進程的功能,與之相關(guān)的proc文件為/proc/(pid)/stat;
⑦顯示系統(tǒng)所有進程的一些信息,包括pid、ppid、占用內(nèi)存大小、優(yōu)先級等,與之相關(guān)的proc文件為/proc/(pid)/stat,/proc/(pid)/statm;
⑧CPU使用率的圖形化顯示(2分鐘內(nèi)的歷史記錄曲線),與之相關(guān)的proc文件為/proc/stat;
⑨內(nèi)存和交換分區(qū)的使用率的圖形化顯示(2分鐘內(nèi)的歷史曲線),與之有關(guān)的proc文件為/proc/meminfo;
⑩在狀態(tài)欄顯示當前時間,未使用到/proc中的文件;
?在狀態(tài)欄顯示當前CPU使用率,與之相關(guān)的proc文件為/proc/stat; ?在狀態(tài)欄顯示當前內(nèi)存使用情況,與之相關(guān)的proc文件為/proc/meminfo; ?用新線程運行一個其他程序,未使用到/proc中的文件; ?關(guān)機功能,未使用到/proc中的文件;(3)功能實現(xiàn)
①獲取并顯示主機名
用fopen函數(shù)打開/proc/sys/kernel/hostname文件,然后以文件指針為輸入流,用fgets從其中讀出一行字符包含主機名,然后用格式化輸出函數(shù)sscanf函數(shù)輸出一個字符串,即主機名。
②獲取并顯示系統(tǒng)啟動的時間
從文件/proc/uptime中獲取系統(tǒng)啟動到現(xiàn)在的運行時間(單位是s),然后調(diào)用time函數(shù)獲取系統(tǒng)當前時間(單位是s),用當前時間秒數(shù)減去運行時間秒數(shù)即為系統(tǒng)啟動的時間秒數(shù),然后調(diào)用localtime函數(shù)將系統(tǒng)啟動時間秒數(shù)轉(zhuǎn)換成tm結(jié)構(gòu)體類型的變量,該變量中的成員包括年份、月份、日期、星期幾、時、分、秒等,再調(diào)用輸出函數(shù)輸出即可。
③顯示系統(tǒng)到目前為止持續(xù)運行的時間
用fopen函數(shù)打開/proc/uptime文件,然后以文件指針為輸入流,用fgets從其中讀出一行字符包含系統(tǒng)運行時間,然后用格式化輸入函數(shù)sscanf從讀取出的字符流中輸入一個float類型的數(shù)到runtime,即系統(tǒng)運行的時間。
④顯示系統(tǒng)的版本號
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
從/proc/sys/kernel/ostype和/proc/sys/kernel/osrelease中讀取系統(tǒng)類型(比如linux)和系統(tǒng)內(nèi)核版本號,處理方法和獲取系統(tǒng)運行時間的方法一樣。得到系統(tǒng)類型和系統(tǒng)內(nèi)核版本號之后,調(diào)用QString類的方法arg將兩個字符串連接起來,再輸出顯示即可。
⑤顯示CPU的型號和主頻大小
打開/proc/cpuinfo文件后發(fā)現(xiàn)CPU有四個,相同的型號,不同的主頻,后來才弄清楚所謂的四個CPU是CPU的四個核心,而“主頻”并不是主頻,而是當前時刻該核心所使用的CPU核心頻率,隨時間而變化的。
弄清楚文件中的內(nèi)容的含義之后,開始處理/proc/cpuinfo,從中讀取CPU的型號和頻率。處理這個文件沒有用到fopen等函數(shù),而是使用了Qt自帶的兩個類QFile和QTextStream,定義一個QFile類型的變量file,并用路徑名“/proc/cpuinfo”初始化該變量,其作用是以只讀方式打開文件/proc/cpuinfo,然后以file的地址作為參數(shù)初始化QTextStream類型的變量stream,其作用是將/proc/cpuinfo文件中的內(nèi)容以字符流的形式存入變量stream中,相當于一個文本流。由于CPU的型號是一樣的,所以只讀取第一個型號名稱即可,根據(jù)CPU型號名稱所在的行,采用while循環(huán)讀取stream中的內(nèi)容,每次讀取一行,當行數(shù)等于CPU型號所在行時,將讀取出的一行賦值給一個QString類型的變量,再調(diào)用QString的方法mid截取CPU型號名稱,file.close()關(guān)閉file。CPU四個核心的主頻處理方法和CPU型號的處理方法一致,參照上述步驟即可。
⑥通過pid或者進程名查詢一個進程,并顯示該進程的詳細信息,提供殺掉該進程的功能
在獲取所有進程信息的時候,獲取到的所有信息已經(jīng)被存儲在一個全局結(jié)構(gòu)體數(shù)組變量中了,所以查詢的時候,先獲取輸入lineEdit中的文本(QString類型),然后將文本與全局結(jié)構(gòu)體數(shù)組變量的每一個數(shù)組元素的name成員和pid成員作比較,若相等,說明待查詢的進程存在,將該進程的詳細信息輸出即可。
殺死進程前先要獲取將要被殺死進程的名稱或者pid,而且該進程必須存在于/proc目錄下,即先查詢一次待殺死的進程,處理方法如上所述。Linux系統(tǒng)提供了kill、pkill等殺死進程的命令,pkill通過pid殺死進程,kill通過進程名稱殺死進程。通過將lineEdit中的內(nèi)容和kill或pkill組成終端命令,然后調(diào)用system函數(shù)執(zhí)行這
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
些命令即可殺死相應(yīng)的進程。
⑦顯示系統(tǒng)所有進程的一些信息,包括pid、ppid、占用內(nèi)存大小、優(yōu)先級等 系統(tǒng)的進程眾多,且進程號從1到幾萬的都有,如果從1開始遍歷訪問,效率就會很低。所以本次實驗我采用的是Linux中對目錄進行操作的函數(shù)opendir(),readdir()。這兩個目錄操作函數(shù)在上學(xué)期的操作系統(tǒng)第三次課程實驗中已經(jīng)學(xué)習(xí)使用過,所以再次使用沒遇到多大的障礙。
實現(xiàn)思路為:聲明一個DIR類型的指針dir,用opendir函數(shù)打開/proc目錄,返回值賦值給dir,然后將dir作為函數(shù)readdir的參數(shù),readdir函數(shù)返回值復(fù)制給dirent結(jié)構(gòu)體指針ptr。ptr指向的結(jié)構(gòu)體包含d_name char數(shù)組成員,即文件或者目錄名,將d_name數(shù)組的0號元素分別和字符?1?、?9?比較,若處于這兩者之間,則表明該文件或者目錄是進程目錄,以該目錄名為參數(shù)調(diào)用獲取進程詳細信息的函數(shù)read_proc。在read_proc函數(shù)中,使用格式化輸出函數(shù)sprintf將參數(shù)目錄名c_pid對應(yīng)目錄下的文件stat的路徑輸出到char數(shù)組filename中,再調(diào)用C++的類ifstream,聲明一個ifstream類性的變量meminfo,用filename初始化meminfo,然后用析取器(>>)從meminfo中輸入數(shù)據(jù)到結(jié)構(gòu)體數(shù)組procInfo的每個元素的成員變量中,析取器(>>)會自動忽略空字符。所需要的進程信息并不是連續(xù)存放在stat文件中的,中間包含有其他不需要顯示的進程信息,解決方法是定義一個string類型的變量temp,根據(jù)stat文件中的信息存放順序,將所有不需要的進程信息全部輸入到temp中。此外還要注意一個問題,進程名稱帶有括號“()”,所以需要將括號去掉,解決方法是使用string類的方法substr,該函數(shù)的參數(shù)有兩個,一個是想截取的字符串首字符在原字符串中的位置,第二個參數(shù)是想截取的字符串末尾字符后面一個字符,在這里就是“)”。處理完畢之后,所需要的關(guān)于進程c_pid的詳細信息都存儲在全局結(jié)構(gòu)體數(shù)組procInfo的元素中了。
循環(huán)采用上述思路,直到所有進程目錄都被處理完畢,所有的進程信息就都存儲在了全局結(jié)構(gòu)體數(shù)組procInfo中,然后用定時器觸發(fā)定時更新全局結(jié)構(gòu)體數(shù)組procInfo中的內(nèi)容。
⑧CPU使用率的圖形化顯示
由于需要畫出CPU使用率兩分鐘內(nèi)的歷史記錄曲線,所以需要計算并存儲120個連續(xù)時刻的CPU利用率。定義一個全局QList變量yList,用于存放CPU使用率。
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
在CPURate函數(shù)中調(diào)用add_point函數(shù),add_point的參數(shù)是cpuRate。在函數(shù)add_point中,首先判斷yList的大小,若大于120,則把yList的隊首元素刪除,保證yList的元素個數(shù)恒等于120;若等于0,則將yList前119個元素初始化為0,這樣的話,CPU歷史記錄曲線就會從右邊向左邊逐漸顯示出來;若大于等于1,則在yList末尾插入新的cpuRate,然后調(diào)用UpdateCPULine函數(shù)畫出記錄曲線。
得到CPU使用率之后,在函數(shù)UpdateCPULine中畫圖。先在QPixmap類型的變量pix上畫曲線,pix相當于一塊畫布,然后再把pix添加到label標簽上。pix的背景色設(shè)置為藍色,然后定義一個QPainter類painter,painter的畫圖設(shè)備就是pix,定義QPen畫筆pen,畫筆顏色設(shè)置為紅色,畫筆寬度為2個像素,設(shè)置完成后,以yList中存儲的cpuRate為縱坐標,以yList的元素下標為橫坐標,并根據(jù)坐標軸單位長度所占實際像素個數(shù)稍微調(diào)整一下每個點的橫縱坐標,然后調(diào)用painter的drawLine方法畫出這些點并依次連接起來,就得到了2分鐘內(nèi)的CPU使用率歷史記錄曲線,而且歷史記錄曲線可以隨著時間從右向左更新。
⑨內(nèi)存和交換分區(qū)的使用率的圖形化顯示
由于需要畫出內(nèi)存使用率兩分鐘內(nèi)的歷史記錄曲線,所以需要計算并存儲120個連續(xù)時刻的內(nèi)存利用率。定義一個全局QList變量yList1,用于存放內(nèi)存使用率。在MemRate函數(shù)中調(diào)用add_point函數(shù),add_point的參數(shù)是memRate。在函數(shù)add_point中,首先判斷yList1的大小,若大于120,則把yList1的隊首元素刪除,保證yList1的元素個數(shù)恒等于120;若等于0,則將yList1前119個元素初始化為0,這樣的話,內(nèi)存使用率歷史記錄曲線就會從右邊向左邊逐漸顯示出來;若大于等于1,則在yList1末尾插入新的memRate,然后調(diào)用UpdateMemLine函數(shù)畫出記錄曲線。
得到內(nèi)存使用率之后,在函數(shù)UpdateMemLine中畫圖。先在QPixmap類型的變量pix上畫曲線,pix相當于一塊畫布,然后再把pix添加到label標簽上。pix的背景色設(shè)置為藍色,然后定義一個QPainter類painter,painter的畫圖設(shè)備就是pix,定義QPen畫筆pen,畫筆顏色設(shè)置為紅色,畫筆寬度為2個像素,設(shè)置完成后,以yList1中存儲的memRate為縱坐標,以yList1的元素下標為橫坐標,并根據(jù)坐標軸單位長度所占實際像素個數(shù)稍微調(diào)整一下每個點的橫縱坐標,然后調(diào)用painter的drawLine方法畫出這些點并依次連接起來,就得到了2分鐘內(nèi)的內(nèi)存使用率歷史記
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
錄曲線,而且歷史記錄曲線可以隨著時間從右向左更新。
⑩在狀態(tài)欄顯示當前時間
調(diào)用QDateTime的方法currentDateTime獲取當前時間time,time是一個QDateTime類型的變量,然后調(diào)用QDateTime的方法toString把time轉(zhuǎn)化成格式為yyyy-MM-dd hh:mm:ss dddd的QString字符串,再在主窗口的狀態(tài)欄顯示輸出即可。?在狀態(tài)欄顯示當前CPU使用率
CPU的使用率是指CPU的使用時間和CPU總時間的比值。因為/proc/stat文件中的所有值都是從系統(tǒng)啟動開始累計到當前時刻,所以計算CPU使用率時需要取兩個采樣點,利用兩個點的差值計算CPU使用率,此次實驗采樣方法是每隔1秒采樣一次。CPU使用率的計算公式為cpuRate=100.0-(idle2-idle1)*100.0/(total2-total1)。定義一個全局結(jié)構(gòu)體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總時間的值等于結(jié)構(gòu)體CPU_USE中7個unsigned int類型的成員值之和。計算之前,調(diào)用get_cpu_use_stat函數(shù)獲取一個CPU狀態(tài),sleep一秒后再調(diào)用該函數(shù)獲取第二個CPU狀態(tài),然后用上述CPU使用率計算公式計算即可。
?在狀態(tài)欄顯示當前內(nèi)存使用情況
內(nèi)存使用率是指已使用的內(nèi)存和總內(nèi)存的比值。內(nèi)存使用率的計算公式為:memRate=(total –(free+buffers+cached))*100.0/total。
定義一個全局結(jié)構(gòu)體MEM_USE,具體定義如下:
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
typedef struct MEM_USE{
unsigned long total;
unsigned long free;
unsigned long buffers;
unsigned long cached;}mem_use;該結(jié)構(gòu)體中的成員的值都來自文件/proc/meminfo,聲明一個ifstream類性的變量meminfo,用/proc/meminfo初始化meminfo,然后用析取器(>>)從meminfo中輸入數(shù)據(jù)到結(jié)構(gòu)體mem_use 的成員變量中,析取器(>>)會自動忽略空字符。所需要的內(nèi)存數(shù)據(jù)信息并不是連續(xù)存放在/proc/meminfo文件中的,中間包含有其他不需要的內(nèi)存數(shù)據(jù)信息,解決方法是定義一個string類型的變量str,根據(jù)/proc/meminfo文件中的信息存放順序,將所有不需要的內(nèi)存數(shù)據(jù)信息全部輸入到str中。得到內(nèi)存使用的數(shù)據(jù)信息之后,使用上述內(nèi)存使用率計算公式計算即可。?用新線程運行一個其他程序
在主窗口中添加一個lineEdit控件,獲取該控件中輸入的程序名稱,然后調(diào)用QProcess類的start方法運行該程序。?關(guān)機功能
由于關(guān)機功能需要輸入密碼獲取root權(quán)限,所以需要想方法在點擊關(guān)機按鈕后輸入密碼。定義一個QString類型的變量passWord,調(diào)用類QInputDialog的方法getText,會彈出一個對話框提示輸入密碼,該方法的返回值即為密碼,將返回值賦值給passWord變量;當對話框的OK按鈕被點擊時,用QString(“echo %1 | sudo-S shutdown-h now”).arg(passWord)初始化QString類型的變量sudo,再把sudo轉(zhuǎn)換成char*類型,然后調(diào)用system函數(shù)執(zhí)行關(guān)機命令。(4)界面設(shè)計
新建一個Qt Widgets Application工程,用setWindowTitle函數(shù)將主窗口的標題改為“proc進程管理器”,設(shè)置窗口的初始大小為(650,500),初始位置為顯示屏左上角,即坐標原點。
在主窗口底部添加一個狀態(tài)欄控件,用QStatusBar實現(xiàn)。狀態(tài)欄中添加三個標簽和一個按鈕,三個標簽分別用于顯示當前時間、CPU使用率、內(nèi)存使用率,這三
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
個信息的顯示函數(shù)都與定時器QTimer綁定,隨時間自動更新,按鈕用于觸發(fā)關(guān)機函數(shù)。
在主窗口的窗體中添加tabWidget控件,設(shè)置四個tab選項卡tab_
1、tab_
2、tab_
3、tab_4。tab_1選項卡用于顯示主機名、系統(tǒng)啟動時間、系統(tǒng)運行時間、系統(tǒng)版本號、CPU型號和主頻等信息,這些內(nèi)容全部用QLabel類的標簽顯示,其中系統(tǒng)運行時間和CPU主頻函數(shù)是槽函數(shù),都和定時器QTimer綁定,隨著時間自動更新。tab_2選項卡用于顯示進程詳細信息,進程詳細信息包括進程名、pid、ppid、內(nèi)存占用和優(yōu)先級,這些信息用tableWidget控件顯示,tableWidget控件設(shè)置為禁止選中、禁止修改,tableWidget的列數(shù)是固定的5列,行數(shù)動態(tài)確定,由獲取所有進程詳細信息的函數(shù)get_pid_info的返回值提供;這樣做的好處是,當創(chuàng)建新進程或者殺死進程時,tableWidget不會出現(xiàn)行數(shù)不夠或者有空行的情況,并且ProcessInfo函數(shù)(即控制顯示進程信息的函數(shù))與QTimer綁定,隨時間定時更新。tab_3選項卡用于提供查詢進程、殺死進程、創(chuàng)建新進程的操作面板,查詢進程的輸入框用lineEdit控件實現(xiàn),該控件的好處是可以直接調(diào)用控件所包含的方法text獲取輸入框的內(nèi)容,便于查詢進程信息;在lineEdit下方放置的是tableWidget控件,同樣,該控件禁止選中、禁止修改,用于顯示查詢的進程詳細信息;tableWidget控件下方是關(guān)閉進程的按鈕,當點擊該按鈕時便會觸發(fā)killProcess函數(shù)關(guān)閉進程;創(chuàng)建進程的進程名輸入框同樣也是用lineEdit控件實現(xiàn),當點擊“運行”按鈕時便會觸發(fā)CreateProcess函數(shù)。tab_4選項卡用于顯示CPU使用率歷史記錄曲線和內(nèi)存使用率歷史記錄曲線。(5)程序運行結(jié)果
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
4.4.3 源代碼
#mainwindow.h,包含各種槽函數(shù)
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include
Q_OBJECT
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
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,獲取主機名、系統(tǒng)運行時間、系統(tǒng)版本號
#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()
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
{
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;
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
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,計算內(nèi)存使用率
#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();
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
} 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();
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
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“<<”內(nèi)存占用/KB“<<”優(yōu)先級“;
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);
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
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“<<”內(nèi)存占用/KB“<<”優(yōu)先級“;
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;
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
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);
}
}
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
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();
}
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告
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();} 心得體會
本次課程設(shè)計,第一個題目很簡單,以前寫過文件拷貝的C語言程序,第一個題目在以前的基礎(chǔ)上用open、read、write等替換fopen、fread、fwrite即可;第二個題目和第三個題目是第一次遇見,在此之前對系統(tǒng)調(diào)用和設(shè)備驅(qū)動程序的知識知之甚少,所以剛開始障礙比較大,但是慢慢地就有了些了解,也就沒那么復(fù)雜了,但是需要細心;第四個題目看起來很復(fù)雜,其實沒那么復(fù)雜,第一題已經(jīng)解決了Qt
華 中 科 技 大 學(xué) 課 程 設(shè) 計 報 告 的使用問題,剩下的就是對/proc文件系統(tǒng)的處理問題,包括文件的讀取、讀取之后對字符串的處理等,這些處理相對來說比較繁瑣,所以花費了不少時間。
這次課設(shè)讓我對Linux的系統(tǒng)調(diào)用、設(shè)備驅(qū)動程序的工作原理、/proc文件系統(tǒng)等有了更深的理解,對Qt的使用比以前更加熟練??偠灾@次課設(shè)讓我收獲很多,受益匪淺。
第三篇:操作系統(tǒng)課設(shè)任務(wù)
一、操作系統(tǒng)課程設(shè)計要求:
1.每個學(xué)生從以下給定題目中選做至少一項,也可以針對操作系統(tǒng)課程實驗已完成的題目進行擴充完善; 2.設(shè)計周周末向各班學(xué)習(xí)委員交源程序、設(shè)計報告的電子版和打印版; 3.編程工具不限
二、操作系統(tǒng)課程設(shè)計題目:(在以下題目中任選一個題目進行設(shè)計)
1.進程同步問題(信號量機制)(任選其一)1)生產(chǎn)者消費者問題 2)哲學(xué)家進餐問題 3)讀者-寫者問題 4)吃水果問題 5)售票員售票問題
2.進程(作業(yè))調(diào)度算法(任選其中三種算法)1)先來先服務(wù)算法 2)短進程(作業(yè))優(yōu)先算法 3)優(yōu)先數(shù)優(yōu)先算法 4)最高響應(yīng)比優(yōu)先算法 5)時間片輪轉(zhuǎn)調(diào)度算法
3.實時調(diào)度算法 1)最早截止時間優(yōu)先 2)最低松弛度優(yōu)選 4.銀行家算法(死鎖避免)
5.動態(tài)分區(qū)分配算法(連續(xù)存儲器管理方式)
首次適應(yīng)算法、循環(huán)首次適應(yīng)算法、最佳適應(yīng)算法、最差適應(yīng)算法 6.頁面置換算法
最佳置換算法OPT、先進先出算法FIFO、最近最久未使用算法LRU 7.磁盤調(diào)度算法
先來先服務(wù)算法、最短尋道時間優(yōu)先算法、掃描算法(電梯調(diào)度算法)8.緩沖池管理
三、操作系統(tǒng)課程設(shè)計任務(wù)書
封皮
指導(dǎo)教師評語
第一部分:需求分析(課題描述、課題目的、理論依據(jù))第二部分:概要設(shè)計(設(shè)計方法、技術(shù)、運行環(huán)境等)第三部分:詳細設(shè)計(流程圖、程序主要代碼)
第四部分:運行結(jié)果及分析(運行結(jié)果(可以截圖)、結(jié)果詳細分析)第五部分:總結(jié)和心得 參考文獻: 附錄:程序源代碼
注:程序詳細代碼附在電子版中即可,打印版可不打印。
課程設(shè)計時間:2018年1月1日——2018年1月5日
第四篇:操作系統(tǒng)課設(shè)程序源
南京工程學(xué)院
課程設(shè)計報告
課 程 名 稱 操作系統(tǒng)原理與應(yīng)用 實 驗 名 稱 儲存管理 院(系、部、中心)
通信工程學(xué)院
專
業(yè)
通信工程
班 級 信息工程111 姓 名 車含喆 學(xué) 號 208110808 起 止 日 期 2014.4.22 指 導(dǎo) 教 師 耿鵬
1、實驗?zāi)康?/p>
1.通過模擬實現(xiàn)請求頁式存儲管理的幾種基本頁面置換算法。2.了解虛擬存儲技術(shù)的特點
3.掌握虛擬存儲請求頁式存儲管理中幾種基本頁面置換算法的基本思想和實現(xiàn)過程,并比較它們的效率。
2、實驗內(nèi)容
3、實驗設(shè)備
PC 1臺,Ubuntu 操作系統(tǒng)
4、實驗總結(jié)
UNIX中,為了提高內(nèi)存利用率,提供了內(nèi)外存進程對換機制;內(nèi)存空間的分配和回收均以頁為單位進行;一個進程只需將其一部分調(diào)入內(nèi)存便可運行;還支持請求調(diào)頁的儲存管理方式。
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 數(shù)據(jù)結(jié)構(gòu)課設(shè) 大整數(shù)計數(shù)器 1.問題描述 實現(xiàn)大整數(shù)(200位以內(nèi)的整數(shù))的加、減、乘、除運算。2.設(shè)計要求 設(shè)計程序?qū)崿F(xiàn)兩個大整數(shù)的四則運算,輸出這兩個大整數(shù)的和、差、積、商及余數(shù)。 3.數(shù)據(jù)結(jié)構(gòu) 本課程設(shè)計采用順序串來實現(xiàn)。4.問題分析 由于整數(shù)數(shù)據(jù)存儲位數(shù)有限,因此引入串的概念,將整型數(shù)據(jù)用字符串進行存儲,利用字符串的一個字符存儲大整數(shù)的一位數(shù)值,然后根據(jù)四則運算規(guī)則,對相應(yīng)位依次進行相應(yīng)運算,同時保存進位,從而實現(xiàn)大整數(shù)精確的運算。具體設(shè)計思路如下: (1)計算大整數(shù)加法時,采用數(shù)學(xué)中列豎式的方法,從個位(即字符串的最后一個字符)開始逐位相加,超過或達到10則進位,同時將該位計算結(jié)果存到另一個字符串中,直至加完大整數(shù)的所有位為止。 (2)計算大整數(shù)減法時,首先調(diào)用庫函數(shù)strcmp判斷這兩個大整數(shù)是否相等,如果相等則結(jié)果為0,否則用compare函數(shù)判斷被減數(shù)和減數(shù)的大小關(guān)系,進而確定結(jié)果為正數(shù)還是負數(shù),然后對齊位依次進行減法,不夠減則向前借位,直至求出每一位減法之后的結(jié)果。 (3)計算大整數(shù)乘法時,首先讓乘數(shù)的每一位都和被乘數(shù)進行乘法運算,兩個乘數(shù)之積與進位相加作為當前位乘積,求得當前位的同時獲取進位值,進而實現(xiàn)大整數(shù)的乘法運算。 (4)計算大整數(shù)除法時,類似做減法,基本思想是反復(fù)做減法,從被除數(shù)里最多能減去多少次除數(shù),所求得的次數(shù)就是商,剩余不夠減的部分則是余數(shù),這樣便可計算出大整數(shù)除法的商和余數(shù)。 需求分析(1)任何一個表達式都是由操作數(shù)、運算符和界限符組成的,我們稱之為單詞.(2)表達式求值首先要符合四則運算規(guī)則: ① 先乘除,后加減 ② 從左到右進行運算 ③ 先括號內(nèi),后括號外(3)功能實現(xiàn): ① 若當前單詞為數(shù)字串,則壓入數(shù)值棧 ② 若當前單詞為運算符并大于運算棧的棧頂符號,則進棧 ③ 若當前單詞為運算符并等于運算棧的棧頂符號,去括號,輸出 ④ 若當前單詞為運算符并小于運算棧的棧頂符號,則進行運算 課程設(shè)計的目的 通過課程設(shè)計全面掌握《C語言程序設(shè)計》關(guān)鍵知識點,掌握C語言中數(shù)組、指針、結(jié)構(gòu)體、文件等方面的基本知識。 通過課程設(shè)計了解并掌握C語言程序設(shè)計的方法,熟悉C程序設(shè)計的開發(fā)環(huán)境及C程序的 調(diào)試過程。 培養(yǎng)學(xué)生查閱參考資料、手冊的自學(xué)能力,通過獨立思考深入鉆研有關(guān)問題,學(xué)會自己分析、解決問題的方法。 課程設(shè)計的任務(wù)和要求 任務(wù): 編程求出輸入的兩個正整數(shù)之和,這兩個正整數(shù)的可能達到200位。 要求: 輸入: 共有兩行,第一行為第1個正整數(shù);第二行為第2個正整數(shù)。 輸出: 2個正整數(shù)之和。 主要參與成員 姓 名 學(xué) 號 系 別 班 級 主要作用(分工) 成果形式 設(shè)計 軟件 作品 其他: 完成情況及以后的拓展設(shè)想 通過用C語言編寫函數(shù)基本實現(xiàn)了大整數(shù)相加這個程序,但該程序仍存在一些不足,還可以加上一些語句使程序具有容錯功能,并且可以正確計算一個負數(shù)和一個正數(shù)相加。 課 程 設(shè) 計 鑒 定 情 況 表 小組鑒定意見 小組長簽名: 年 月 日 指導(dǎo)教師意見 教師簽名: ****年**月**日 課程設(shè)計成績 優(yōu) 良 及格 不及格 教研室意見 年 月 日 備注 《C語言程序設(shè)計》課程設(shè)計報告書 作者:廖 序 課程設(shè)計概述 課程設(shè)計名稱 大整數(shù)相加 任務(wù)要求: 編程求出輸入的兩個正整數(shù)之和,這兩個正整數(shù)的可能達到200位。 輸入: 共有兩行,第一行為第1個正整數(shù);第二行為第2個正整數(shù)。 輸出: 2個正整數(shù)之和。開發(fā)環(huán)境: C語言。C語言是目前世界上流行、使用最廣泛的高級程序設(shè)計語言。1972年,C語言在美國貝爾實驗室里問世,后來又被多次改進,并出現(xiàn)了多種版本。80年代初,美國國家標準化協(xié)會(ANSI),根據(jù)C語言問世以來各種版本對C語言的發(fā)展和擴充,制定了ANSIC標準。 目前,在微機上廣泛使用的C語言編譯系統(tǒng)有MicrosoftC、Turbo C、Borland C等。這些C語言版本不僅實現(xiàn)了ANSIC標準,而且在此基礎(chǔ)上各自作了一些擴充,使之更加方便、完美。 C語言的特點: C語言是一種結(jié)構(gòu)化語言。它層次清晰,便于按模塊化方式組織程序,易于調(diào)試和維護。C語言的表現(xiàn)能力和處理能力極強。它不僅具有豐富的運算符和數(shù)據(jù)類型,便于實現(xiàn)各類復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。它還可以直接訪問內(nèi)存的物理地址,進行位(bit)一級的操作。 由于C語言實現(xiàn)了對硬件的編程操作,因此C語言集高級語言和低級語言的功能于一體。既可用于系統(tǒng)軟件的開發(fā),也適合于應(yīng)用軟件的開發(fā)。 此外,C語言還具有效率高,可移植性強等特點。因此廣泛地移植到了各類各型計算機上,從而形成了多種版本的C語言。 參考資料 李錚、葉艷冰、汪德俊,C語言程序設(shè)計基礎(chǔ)與應(yīng)用,清華大學(xué)出版社,2005 [2]CSDN技術(shù)中心 二、概要設(shè)計 為了實現(xiàn)大整數(shù)相加這個程序,將程序劃分為了三個模塊: 輸入數(shù)據(jù)。運算。輸出結(jié)果。 首先定義了子函數(shù)Input()來存儲用戶輸入的兩個加數(shù),為了滿足任意位數(shù)的兩個大整數(shù)相加,在子函數(shù)Input()中嵌套調(diào)用子函數(shù)Init()使sum數(shù)組里面存放的數(shù)初始化為”0”。 然后定義子函數(shù)Long_Add()使兩個大整數(shù)作加法運算,從后面往前面相加,附帶進位。定義子函數(shù)Output()實現(xiàn)輸出結(jié)果。 最后如下圖所示,在主函數(shù)main中調(diào)用Input(),Long_Add(),Output()三個子函數(shù)實現(xiàn)程序。 三、詳細設(shè)計 程序的流程圖: 四、調(diào)試過程 第一次 測試數(shù)據(jù)a=***7,b=111111 編譯運行后不能輸出結(jié)果,檢查函數(shù)后編譯正確。再次分析,發(fā)現(xiàn)如果直接把a,b,sum定義為unsigned int型的話,計算出來的和的范圍只能在0~65535之間,否則就會出現(xiàn)錯誤。嘗試將a,b,sum存放到字符數(shù)組中,從個位開始,一位一位相加。 第二次 測試數(shù)據(jù)a=***7,b=111111 編譯運行后仍不能輸出結(jié)果。分析原因,在用于輸出的子函數(shù)Output()中,輸出數(shù)組字符數(shù)組sum[]前未確定和的最高非零位。 嘗試加入for(i=0;i 第三次 測試數(shù)據(jù)a=99999919,b=99 編譯運行后發(fā)現(xiàn)計算出來結(jié)果不正確。經(jīng)過分析,函數(shù)中沒有對最后 一個進位進行處理。 嘗試加入while(carry > 0)語句,再次進行調(diào)試。 { tempsum = sum[i]-'0'+carry;sum[i] = tempsum%10+'0';carry = tempsum/10;i--;} 第四次 測試數(shù)據(jù)a=99999919,b=99 編譯運行后得到正確結(jié)果。 第五次 隨意輸入幾組數(shù)據(jù)進行測試,結(jié)果都是正確的。程序得到實現(xiàn)。 五、結(jié)論與體會 通過不斷的調(diào)試、修改,本課程設(shè)計最終實現(xiàn)了200位以內(nèi)的兩個大整數(shù)相加,但程序還 可以進一步完善,程序中仍存在一些不足之處,比如缺少容錯功能,不能準確計算負整數(shù)加正整數(shù),等等問題 雖然C語言程序設(shè)計在上學(xué)期做為我們的必修課已經(jīng)學(xué)習(xí)過了,但書到用時方恨少,這次課程設(shè)計的學(xué)習(xí)程序設(shè)計中暴露出的我自身的問題更是非常明顯。 一開始看到題目認為非常簡單,直接將兩個數(shù)都定義為整型。編寫程序并運行后發(fā)現(xiàn)并不能達到題目的要求,計算出來的和只能小于等于65535,否則就會出現(xiàn)錯誤。分析后,將數(shù)據(jù)作為字符串來處理,用for循環(huán)語句從存數(shù)的字符數(shù)組中一位一位的取數(shù)出來,按照數(shù)位對齊,從個位開始,按位相加,逢十進一的運算規(guī)則進行運算。最后用字符輸出函數(shù)putchar()輸出計算出來的結(jié)果。由于程序偏大且較復(fù)雜,將程序劃分為了輸入數(shù)據(jù)、運算、輸出數(shù)據(jù)三個子程序。數(shù)次編譯調(diào)試后,最終使程序得以實現(xiàn)。 經(jīng)過三個星期的上機實踐學(xué)習(xí),使我對C語言有了更進一步的認識和了解,讓我能夠進一步的掌握和運用C語言來編寫程序。要想學(xué)好C語言要重在實踐,要通過不斷的上機操作才能更好地學(xué)習(xí)它,通過實踐,我也發(fā)現(xiàn)我的好多不足之處和薄弱環(huán)節(jié)。 首先,基礎(chǔ)掌握不牢固,對于C語言中的許多基本語法尚沒有熟練掌握,在設(shè)計過程中仍需請教其它同學(xué),查閱課本,設(shè)計效率很低。 其次,經(jīng)典算法掌握不牢。在完成作業(yè)的過程中還需查閱書籍和借鑒他人。 再次,程序量過大的時候,頭緒理不清。雜亂無章,無系統(tǒng)性,不便調(diào)試和閱覽,自己也易于出錯。 并且對C語言中經(jīng)常出現(xiàn)的錯誤也不了解,通過實踐,使我在這幾個方面的認識有所提高。 通過實踐的學(xué)習(xí),我認到學(xué)好計算機要重視實踐操作,不僅僅是學(xué)習(xí)C語言,還是其它的語言,以及其它的計算機方面的知識都要重在實踐,所以后在學(xué)習(xí)過程中,我會更加注視實踐操作,使自己便好地學(xué)好計算機。 六、源程序清單 #include t;string.h> #define Max 1000 char sum[Max+1];/*和*/ char a[Max],b[Max];/*兩個加數(shù)*/ int len1,len2;void Input(char a[],char b[]){ int i,len;void Init(char a[]);/*對Init()函數(shù)進行聲明*/ 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;第五篇:數(shù)據(jù)結(jié)構(gòu)課設(shè)