實驗一 幾種操作系統的界面
一、目的和要求
- 目的
本實驗的目的是使學生熟悉1—2種操作系統的界面,在熟練使用機器的基礎上,能瞭解各種操作命令和系統調用在系統中的大致工作過程。也就是通過操作系統的外部特徵,逐步深入到操作系統的內部實質內容中去。
- 要求
- 能熟練的在1—2種操作系統的環境下工作,學會使用各種命令,熟悉系統提供的各種功能,主動而有效地使用計算機。
- 熟悉系統實用程序的調用方法和各種系統調用模塊的功能和作用
二、內容
在某種操作系統的環境下建立、修改、運行、打印源程序和結果,最後撤消一個完整的程序。
提示:可按下述步驟進行
- 編寫一個完整的源程序,通過編輯命令送入機器,建立源程序文件;
- 編譯該源文件,建立相應的目標文件;
- 編譯有錯時,再用編輯命令修改源文件,消除全部詞法和語法錯誤;
- 連接目標文件,形成可執行文件;
- 執行該文件,得到結果;
- 打印輸出源程序和運行結果;
- 撤消本次實驗中形成的所有文件。
三、實驗步驟及程序流程圖
1.建立工作路徑
mkdir zhou
新建目錄
dir
顯示當前目錄下的所有文件信息
2.編寫源文件
- 將文件的擴展名改成Homework.java,然後編譯形成java字節碼文件。
Javac Homework.java
- 運行java文件
java Homework
- 認識ubuntu操作系統
- java程序編譯運行過程
四、程序清單
Java源代碼
import java.awt.Choice;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.Border;
public class Homework {
public static void main(String[] args) {
new MyFrame("周大哥的購物車").load();
}
}
class MyFrame extends JFrame {
JButton b1;
JButton b2;
JButton b3;
JButton b4;
JPanel p1;
JPanel p2;
JPanel p3;
Vector<String> vLeft;
Vector<String> vRight;
JList j2;
JList j1;
MyFrame(String name) {
// this.setBackground(Color.BLUE);
this.setTitle(name);
// this.setIconImage(new );
b1 = new JButton(">>");
// b1.setContentAreaFilled(false);
b1.setBorder(BorderFactory.createRaisedBevelBorder());
b2 = new JButton(">");
b2.setBorder(BorderFactory.createRaisedBevelBorder());
b3 = new JButton("<<");
b3.setBorder(BorderFactory.createRaisedBevelBorder());
b4 = new JButton("<");
b4.setBorder(BorderFactory.createRaisedBevelBorder());
p1 = new JPanel();
p1.setBackground(Color.PINK);
//p1.setPreferredSize(new Dimension(300, 800));
b2.addMouseListener(new Mon1());
b4.addMouseListener(new Mon1());
b1.addMouseListener(new Mon2());
b3.addMouseListener(new Mon2());
// 中間的面板設置4行1列
p2 = new JPanel(new GridLayout(4, 1, 0, 20));
p2.setBackground(Color.red);
p3 = new JPanel();
p3.setBackground(Color.PINK);
p3.setBounds(100, 100, 400, 500);
vRight = new Vector<String>();
vRight.add("書");
vRight.add("筆");
vRight.add("橡皮");
vRight.add("眼鏡");
vRight.add("手機");
vLeft = new Vector<String>();
vLeft.add("羽絨服");
vLeft.add("褲子");
vLeft.add("襯衣");
vLeft.add("運動鞋");
vLeft.add("揹包");
vLeft.add("球拍");
j1 = new JList(vLeft);
//j1.setPreferredSize(new Dimension(80,10 ));
j1.setFont(new Font("宋體", Font.BOLD + Font.ITALIC, 30));
j1.setSelectionBackground(Color.yellow);
j2 = new JList(vRight);
j2.setFont(new Font("宋體", Font.BOLD + Font.ITALIC, 30));
j2.setSelectionBackground(Color.yellow);
//j2.setPreferredSize(new Dimension(100, 8));
}
void load() {
this.setLayout(new FlowLayout(FlowLayout.CENTER, 50, 50));
j1.add(b1);
j1.setVisibleRowCount(10);
p1.add(new JScrollPane(j1));
add(p1);
// 在面板內添加按鈕
p2.add(b1);
p2.add(b2);
p2.add(b3);
p2.add(b4);
add(p2);
// p3.add(t2);
j2.setVisibleRowCount(10);
p3.add(new JScrollPane(j2));
add(p3);
pack();
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
}
class Mon2 implements MouseListener {
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
JButton button = (JButton) e.getSource();
if (button.getText().equals(">>")) {
vRight.addAll(vLeft);
vLeft.clear();
// System.out.println("我執行了");
} else {
vLeft.addAll(vRight);
vRight.clear();
}
j1.updateUI();
j2.updateUI();
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
class Mon1 implements MouseListener {
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
JButton t = (JButton) e.getSource();
// 向右移動
if (t.getText().equals(">")) {
int num[] = j1.getSelectedIndices();
if (num.length == 0 || vLeft.size() == 0) {
JOptionPane.showMessageDialog(null, "親,請選擇選項後移動");
} else if (num.length >= 1) {
Vector<String> temp = new Vector<String>();
for (int i : num) {
// if((vLeft.get(i))!=null)
temp.add(vLeft.get(i));
}
for (String i : temp) {
vLeft.remove(i);
vRight.add(i);
}
}
} // 向左移動
else if (t.getText().equals("<")) {
int num[] = j2.getSelectedIndices();
Vector<String> temp = new Vector<String>();
if (num.length == 0 || vRight.size() == 0) {
JOptionPane.showMessageDialog(null, "親,請選擇好後移動");
} else {
for (int i : num) {
// if((vRight.get(i))!=null)
temp.add(vRight.get(i));
}
for (String aa : temp) {
vRight.remove(aa);
vLeft.add(aa);
}
}
}
j2.updateUI();
j1.updateUI();
j1.setSelectedIndex(0);
j2.setSelectedIndex(0);
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
}
五、心得體會
實踐是檢驗真理的唯一標準,通過對目前市場上的windows和ubuntu操作系統的認識,讓我對操作系統有了新的理解和應用。Ubuntu系統有以下幾方面的優點:
1.高效的文件管理系統,一般情況下不需要碎片整理
2.產生的系統垃圾很少,系統不會隨着使用時間的增多而越來越卡
3.拷貝文件速度快,Win10達到5M/S,Ubuntu達到20M/S
4.系統安全穩定,漏洞修復快,極少中病毒
5.權限管理很嚴格,避免用戶誤操作
6.DIY界面,改善用戶體驗,自由度高(對UI有追求的同學可盡情折騰)
7.強大的命令行,基本上所有操作可在上面執行(瞬間逼格升幾個Lev)
8.無軟件捆綁行爲,桌面無廣告彈窗行爲
9.無盜版系統這一說法,開源免費正版
而Windows10的優點如下:
1.軟件多,軟件多,軟件多(重要的事情說三遍)
2.操作方式對電腦小白友好,上手快 。
3.使用普及率高,同事間協助合作方便。.
4.Win10針對Modern應用進行優化,提升用戶體驗(界面簡潔,運行流暢,去除少用功能,保留核心有用的功能,安裝包體積小) 。
5.支持大量驅動,充分發揮硬件性能。
在實際開發中,應當按照自己的項目需求來恰當選擇。文字/命令行界面雖然沒有圖形界面美觀,但操作響應速度快,執行穩定,不容易出錯。
實驗二 進程調度程序設計
一、目的和要求
- 目的
進程是操作系統最重要的概念之一,進程調度是操作系統的主要內容,本實驗要求學生獨立地用高級語言編寫一個進程調度程序,調度算法可任意選擇或自行設計,本實驗可使學生加深對進程調度和各種調度算法的理解。
- 要求
- 設計一個有幾個進程併發執行的進程調度程序,每個進程由一個進程控制塊(PCB)表示,進程控制塊通常應包括下述信息:進程名,進程優先數,進程需要運行的時間,佔用CPU的時間以及進程的狀態等,且可按照調度算法的不同而增刪。
- 調度程序應包含2—3種不同的調度算法,運行時可以任選一種,以利於各種方法的分析和比較。
- 系統應能顯示或打印各進程狀態和參數的變化情況,便於觀察。
二、示例
- 題目 本程序可選用優先數法或簡單輪轉法對五個進程進行調度。每個進程處於運行R(run)、就緒W(wait)和完成F(finish)三種狀態之一,並假定起始狀態都是就緒狀態W。
爲了便於處理,程序中進程的運行時間以時間片爲單位計算。各進程的優先數或輪轉時間片數、以及進程需要運行的時間片數,均由僞隨機數發生器產生。
進程控制塊結構如表2-1所示:
表2-1PCB
進程標識符 |
鏈指針 |
優先數/輪轉時間片數 |
佔用CPU時間片數 |
進程所需時間片數 |
進程狀態 |
進程控制塊鏈結構如圖2-1所示:
RUN HEAD TAIL
1 |
┇ |
R |
3 |
┇ |
W |
5 |
┇ |
W |
W |
0 |
┇ |
2 |
…
圖2-1 進程控制塊鏈結構
其中:RUN—當前運行進程指針;
HEAD—進程就緒鏈鏈首指針;
TAIL—進程就緒鏈鏈尾指針。
2. 算法與框圖程序框圖如圖2-2所示。
priority |
是 |
輸入調度算法alog |
開始 |
alog=priority/round robin? |
生成並按優先數大小排列進程控制塊鏈 |
進程時間片數爲0? |
從鏈首取一個進程投入運行 |
生成並按進入次序 排列進程控制塊鏈 |
鏈首進程投入運行 |
時間片到,進程時間片 數減1,優先數減3 |
運行進程退出,排到進程鏈尾部 |
撤消該進程 |
鏈首進程投入運行 |
時間片到,進程時間片數 減1,佔用CPU時間加1 |
優先數大於鏈首進程? |
進程時間片數爲0? |
撤消該進程 |
運行進程退出,按優先數插入進程鏈 |
從鏈首取一個進程投入運行 |
結束 |
結束 |
進程隊列空? |
進程隊列空? |
是 |
是 |
是 |
否 |
否 |
否 |
否 |
否 |
是 |
round robin |
佔用處理機時間片到? |
否 |
是 |
圖2-2 進程調度框圖
(1)優先數法。 進程就緒鏈按優先數大小從大到小排列,鏈首進程首先投入運行。每過一個時間片,運行進程所需運行的時間片數減1,說明它已運行了一個時間片,優先數也減3。理由是該進程如果在一個時間片中完成不了,優先級應降低一級。接着比較現行進程和就緒鏈鏈首進程的優先數,如果仍是現行進程高或者相同,就讓現行進程繼續運行,否則,調度就緒鏈鏈首進程投入運行。原運行進程再按其優先數大小插入就緒鏈,且改變它們對應的進程狀態,直至所有進程都運行完各自的時間片數。
(2)簡單輪轉法。 進程就緒鏈按各進程進入的先後次序排列,鏈首進程首先投入運行。進程每次佔用處理機的輪轉時間按其重要程度登入進程控制塊中的輪轉時間片數記錄項(相應於優先數法的優先數記錄項位置)。每過一個時間片,運行進程佔用處理機的時間片數加1,然後比較佔用處理機的時間片數是否與該進程的輪轉時間片數相等,若相等說明已到達輪轉時間,應將現運行進程排到就緒鏈末尾,調度鏈首進程佔用處理機,且改變它們的進程狀態,直至所有進程完成各自的時間片。
三、實驗代碼:
#include<iostream>
#include<string>
#include<time.h>
using namespace std;
int n;
class PCB
{
public:
int priorityNumber;//進程優先數
int occupy;//進程運行CPU時間
int pieceOftime;//輪轉時間片
int need;//還需要時間
int Counter;
string processName;//進程名
string state;//進程狀態
PCB * next;
};
PCB * run = NULL;
PCB * ready = NULL;
PCB * finish = NULL;
PCB * tial = ready;
void Dtime(int t);
void Prinft(int a)
{
if(a==1)
{
cout<<" 進程"<<"\t"<<"優先數"<<"\t"<<"還需要時間"<<"\t"<<"已運行時間"<<"\t"<<"狀態:"<<endl;
}
else
cout<<" 進程"<<"\t"<<"已運行時間"<<"\t"<<"還需要時間"<<"\t"<<"計數器"<<"\t"<<"時間片"<<"\t"<<"狀態"<<endl;
}
void Prinft(int b,PCB * p)
{
if(b==1)
{
cout<<p->processName<<"\t\t"<<p->priorityNumber<<"\t"<<p->need<<"\t\t"<<p->occupy<<"\t\t"<<p->state<<endl;
}
else
cout<<p->processName<<"\t\t"<<p->occupy<<"\t\t"<<p->need<<"\t\t"<<p->Counter<<"\t"<<p->pieceOftime<<"\t"<<p->state<<endl;
}
void display(int c)
{
PCB *p;
if(run!=NULL)
Prinft(c,run);
//Dtime(2);
p=ready;
while(p!=NULL)
{
Prinft(c,p);
p=p->next;
}
//Dtime(2);
p=finish;
while(p!=NULL)
{
Prinft(c,p);
p=p->next;
}
}
void insert(PCB *p)//插入就緒隊列按Pri大小
{
PCB *S1,*S2;
if(ready==NULL)
{
p->next = NULL;
ready = p;
}
else
{
S1 = ready;
S2 = S1;
while(S1!=NULL)
{
if(S1->priorityNumber >= p->priorityNumber)
{
S2 = S1;
S1 = S1->next;
}
else
break;
}
if(S2->priorityNumber >= p->priorityNumber)
{
S2->next = p;
p->next = S1;
}
else
{
p->next = ready;
ready = p;
}
}
}
bool CTProcessOfPri()
{
PCB * Node;
cout <<"請輸入創建進程的數目:"<<endl;
cin >>n;
for(int j = 0;j < n; j++)
{
Node = new PCB;
if(Node==NULL)
return false;
else
{
cout <<"親,請輸入進程的名稱,進程需CPU時間例如:process 45"<<endl;
cin >>Node->processName>>Node->need;
Node->occupy = 0;
Node->state ="就緒態";
Node->priorityNumber =Node->need;
cout <<"進程"<<Node->processName<<"創建完畢!"<<endl;
}
insert(Node);
}
return true;
}
void priorityNumberority(int i)
{
run = ready;
ready = ready->next;
run->state = "運行態";
Prinft(i);
while(run!=NULL)
{
run->occupy=run->occupy+1;
run->need=run->need-1;
run->priorityNumber=run->priorityNumber-1;
if(run->need==0)
{
run->state = "完成";
run->next = finish;
finish = run;
run=NULL;
if(ready!=NULL)
{
run = ready;
run->state = "運行態";
ready = ready->next;
}
}
else if((ready!=NULL)&&(run->priorityNumber<ready->priorityNumber))
{
run->state="就緒態";
insert(run);
run = ready;
run->state = "運行態";
ready = ready->next;
}
display(i);
}
}
void queue(PCB *p)
{
if(ready==NULL)
{
p->next = NULL;
ready = p;
tial = p;
}
else
{
tial->next = p;
tial = p;
p->next = NULL;
}
}
bool CTProcessOfRuntime()
{
PCB * Node;
int m;
cout <<"請輸入創建進程的數目:"<<endl;
cin >>n;
cout <<"輸入時間片:"<<endl;
cin >>m;
for(int j = 0;j < n; j++)
{
Node = new PCB;
if(Node==NULL)
return false;
else
{
cout <<"親,請輸入進程的名稱,進程需CPU時間例如:process 8"<<endl;
cin >>Node->processName>>Node->need;
Node->occupy = 0;
Node->state ="就緒態";
Node->Counter = 0;
Node->pieceOftime = m;
cout <<"進程"<<Node->processName<<"創建完畢!"<<endl;
}
queue(Node);
}
return true;
}
void Runtime(int c)
{
run = ready;
ready = ready->next;
run->state = "運行態";
Prinft(c);
while(run!=NULL)
{
run->occupy=run->occupy+1;
run->need=run->need-1;
run->Counter = run->Counter + 1;
if(run->need==0)
{
run->state = "完成";
run->next = finish;
finish = run;
run = NULL;
if(ready!=NULL)
{
run = ready;
ready = ready->next;
}
}
else if(run->Counter == run->pieceOftime)
{
run->Counter = 0;
run->state = "就緒態";
queue(run);
run=NULL;
if(ready!=NULL)
{
run = ready;
run->state = "運行態";
ready = ready->next;
}
}
display(c);
}
}
int main()
{
string i="";
cout <<" 功能選項:"<<endl;
cout <<"q鍵退出"<<endl;
cout <<"輸入p選擇優先數調度算法"<<endl;
cout <<"輸入x選擇循環時間片輪轉算法"<<endl;
cin >>i;
if(i=="p") {
CTProcessOfPri();
priorityNumberority(1);
}
else if(i=="x"){
CTProcessOfRuntime();
Runtime(2);
}
else if(i=="q"){
return 0;
}
}
void Dtime(int t)
{
time_t current_time;
time_t start_time;
time(&start_time);
do
{
time(& current_time);
}while((current_time-start_time)<t);
}
/*
1.優先數調度算法
5
a 3
b 2
c 10
d 4
e 8
2.循環時間片輪轉算法
5
10
a 3
b 2
c 10
d 4
e 8
*/
四、實驗結果:
優先數調度
進程 優先數 還需要時間 已運行時間 狀態:
c 9 9 1 運行態
e 8 8 0 就緒態
d 4 4 0 就緒態
a 3 3 0 就緒態
b 2 2 0 就緒態
c 8 8 2 運行態
e 8 8 0 就緒態
d 4 4 0 就緒態
a 3 3 0 就緒態
b 2 2 0 就緒態
e 8 8 0 運行態
c 7 7 3 就緒態
d 4 4 0 就緒態
a 3 3 0 就緒態
b 2 2 0 就緒態
e 7 7 1 運行態
c 7 7 3 就緒態
d 4 4 0 就緒態
a 3 3 0 就緒態
b 2 2 0 就緒態
c 7 7 3 運行態
e 6 6 2 就緒態
d 4 4 0 就緒態
a 3 3 0 就緒態
b 2 2 0 就緒態
c 6 6 4 運行態
e 6 6 2 就緒態
d 4 4 0 就緒態
a 3 3 0 就緒態
b 2 2 0 就緒態
e 6 6 2 運行態
c 5 5 5 就緒態
d 4 4 0 就緒態
a 3 3 0 就緒態
b 2 2 0 就緒態
e 5 5 3 運行態
c 5 5 5 就緒態
d 4 4 0 就緒態
a 3 3 0 就緒態
b 2 2 0 就緒態
c 5 5 5 運行態
d 4 4 0 就緒態
e 4 4 4 就緒態
a 3 3 0 就緒態
b 2 2 0 就緒態
c 4 4 6 運行態
d 4 4 0 就緒態
e 4 4 4 就緒態
a 3 3 0 就緒態
b 2 2 0 就緒態
d 4 4 0 運行態
e 4 4 4 就緒態
a 3 3 0 就緒態
c 3 3 7 就緒態
b 2 2 0 就緒態
e 4 4 4 運行態
a 3 3 0 就緒態
c 3 3 7 就緒態
d 3 3 1 就緒態
b 2 2 0 就緒態
e 3 3 5 運行態
a 3 3 0 就緒態
c 3 3 7 就緒態
d 3 3 1 就緒態
b 2 2 0 就緒態
a 3 3 0 運行態
c 3 3 7 就緒態
d 3 3 1 就緒態
b 2 2 0 就緒態
e 2 2 6 就緒態
c 3 3 7 運行態
d 3 3 1 就緒態
b 2 2 0 就緒態
e 2 2 6 就緒態
a 2 2 1 就緒態
d 3 3 1 運行態
b 2 2 0 就緒態
e 2 2 6 就緒態
a 2 2 1 就緒態
c 2 2 8 就緒態
d 2 2 2 運行態
b 2 2 0 就緒態
e 2 2 6 就緒態
a 2 2 1 就緒態
c 2 2 8 就緒態
b 2 2 0 運行態
e 2 2 6 就緒態
a 2 2 1 就緒態
c 2 2 8 就緒態
d 1 1 3 就緒態
e 2 2 6 運行態
a 2 2 1 就緒態
c 2 2 8 就緒態
d 1 1 3 就緒態
b 1 1 1 就緒態
a 2 2 1 運行態
c 2 2 8 就緒態
d 1 1 3 就緒態
b 1 1 1 就緒態
e 1 1 7 就緒態
c 2 2 8 運行態
d 1 1 3 就緒態
b 1 1 1 就緒態
e 1 1 7 就緒態
a 1 1 2 就緒態
c 1 1 9 運行態
d 1 1 3 就緒態
b 1 1 1 就緒態
e 1 1 7 就緒態
a 1 1 2 就緒態
d 1 1 3 運行態
b 1 1 1 就緒態
e 1 1 7 就緒態
a 1 1 2 就緒態
c 0 0 10 完成
b 1 1 1 運行態
e 1 1 7 就緒態
a 1 1 2 就緒態
d 0 0 4 完成
c 0 0 10 完成
e 1 1 7 運行態
a 1 1 2 就緒態
b 0 0 2 完成
d 0 0 4 完成
c 0 0 10 完成
a 1 1 2 運行態
e 0 0 8 完成
b 0 0 2 完成
d 0 0 4 完成
c 0 0 10 完成
a 0 0 3 完成
e 0 0 8 完成
b 0 0 2 完成
d 0 0 4 完成
c 0 0 10 完成
循環時間片輪轉
進程 已運行時間 還需要時間 計數器 時間片 狀態
a 1 2 1 10 運行態
b 0 2 0 10 就緒態
c 0 10 0 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
a 2 1 2 10 運行態
b 0 2 0 10 就緒態
c 0 10 0 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
b 0 2 0 10 就緒態
c 0 10 0 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
a 3 0 3 10 完成
b 1 1 1 10 就緒態
c 0 10 0 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
a 3 0 3 10 完成
c 0 10 0 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
b 2 0 2 10 完成
a 3 0 3 10 完成
c 1 9 1 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
b 2 0 2 10 完成
a 3 0 3 10 完成
c 2 8 2 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
b 2 0 2 10 完成
a 3 0 3 10 完成
c 3 7 3 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
b 2 0 2 10 完成
a 3 0 3 10 完成
c 4 6 4 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
b 2 0 2 10 完成
a 3 0 3 10 完成
c 5 5 5 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
b 2 0 2 10 完成
a 3 0 3 10 完成
c 6 4 6 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
b 2 0 2 10 完成
a 3 0 3 10 完成
c 7 3 7 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
b 2 0 2 10 完成
a 3 0 3 10 完成
c 8 2 8 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
b 2 0 2 10 完成
a 3 0 3 10 完成
c 9 1 9 10 就緒態
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
b 2 0 2 10 完成
a 3 0 3 10 完成
d 0 4 0 10 就緒態
e 0 8 0 10 就緒態
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
d 1 3 1 10 就緒態
e 0 8 0 10 就緒態
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
d 2 2 2 10 就緒態
e 0 8 0 10 就緒態
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
d 3 1 3 10 就緒態
e 0 8 0 10 就緒態
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
e 0 8 0 10 就緒態
d 4 0 4 10 完成
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
e 1 7 1 10 就緒態
d 4 0 4 10 完成
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
e 2 6 2 10 就緒態
d 4 0 4 10 完成
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
e 3 5 3 10 就緒態
d 4 0 4 10 完成
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
e 4 4 4 10 就緒態
d 4 0 4 10 完成
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
e 5 3 5 10 就緒態
d 4 0 4 10 完成
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
e 6 2 6 10 就緒態
d 4 0 4 10 完成
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
e 7 1 7 10 就緒態
d 4 0 4 10 完成
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
e 8 0 8 10 完成
d 4 0 4 10 完成
c 10 0 10 10 完成
b 2 0 2 10 完成
a 3 0 3 10 完成
--------------------------------
Process exited after 14.68 seconds with return value 0
請按任意鍵繼續. . .
五、心得體會:
紙上得來終覺淺,總得要實踐一把才印象深刻,對上課所學知識才能真正理解消化。爲了能使程序併發的執行,並且可以對併發執行的程序加以控制,引入進程。爲了使參與併發執行的每個程序都能獨立運行,爲每個進程配置一個進程控制塊PCB,用PCB來描述進程的基本情況和活動過程,進而控制和管理進程。這樣由程序段、相關的數據段和PCB三部分構成了進程實體。進程是程序的一次執行。
進程是一個程序及其數據在處理上順序執行時所發生的的活動。
進程是具有獨立功能的程序在一個數據集合上運行的過程它是系統進行資源分配的獨立單位。進程是一個資源的擁有者,如果頻繁的進行創建撤銷切換會造成很大的時空開銷。所以,引入線程,將線程作爲調度和分派的基本單位,進程作爲資源分配的獨立單位。各種調度算法之間的靈活使用對於操作系統的快速、穩定地執行具有重要的意義。
實驗三 存儲管理程序設計
一、目的和要求
- 目的
存儲管理的主要功能之一是合理地分配主存空間。請求頁式管理是一種常用的虛擬存儲管理技術。
本實驗的目的是通過請求頁式存儲管理中頁面置換算法的模擬設計,來了解虛擬存儲技術的特點,掌握請求頁式存儲管理的頁面置換算法。
- 要求
模擬頁式虛擬存儲管理中硬件的地址轉換和缺頁中斷的處理過程,並用先進先出調度算法(FIFO)處理缺頁中斷。
二、提示
- 爲了裝入一個頁面而必須調出一頁時,如果被選中調出的頁面在執行中沒有修改過,則不必把該頁重新寫到磁盤上(因磁盤上已有副本)。因此,在頁表中可以增加是否修改過的標誌,當執行“存”指令、“寫”指令時把對應頁的修改標誌置成“1”,表示該頁修改過,否則爲“0”,表示該頁未修改過。頁表格式如表3-1所示。
表3-1 頁表格式
頁 號 |
標 志 |
主存塊號 |
修改標誌 |
磁盤上的位置 |
|
|
|
|
|
- 設計一個地址轉換程序來模擬硬件的地址轉換和缺頁中斷處理過程。當訪問的頁在主存時則形成絕對地址,但不去模擬指令的執行,可用輸出轉換後的絕對地址來表示一條指令已完成。當訪問的頁不在主存時則輸出“*該頁頁號”來表示硬件產生了一次缺頁中斷。模擬地址轉換的程序流程如圖3-1所示。
- 編制一個FIFO頁面調度程序。FIFO頁面調度算法總是先調出作業中最先進入主存的那一頁,因此,可以用一個數組來構成頁號隊列。數組中每個元素是該作業已在主存的頁面號,假定分配給作業的主存塊數爲m,且該作業開始的m頁已裝入主存,則數組可由m個元素組成:
P[0],P[1],…,P[m-1]
它們的初值爲P[0]∶=0,P[1]∶=1,…,P[m-1]∶= m-1
用一指針k指示當要裝入新頁時應調出的頁在數組的位置,k的初值爲“0”。
j∶= P[k]
|
j頁的修改標誌=1? |
輸出“OUTj” |
P[k]∶=L k∶=(k+1) mod m |
修改頁表 |
輸出“IN L” |
取一條指令 |
開始 |
頁標誌=1? |
輸出絕對地址 |
取一條指令 |
輸出“﹡頁號” |
取指令中訪問的頁號=>L |
查頁表 |
形成絕對地址 |
置L頁修改標誌”1” |
結束 |
是”存”指令? |
有後繼指令? |
否(產生缺頁中斷) |
是 |
否 |
否 |
否 |
是 |
是 |
模擬硬件 地址轉換 |
模擬FIFO頁面調度 |
是 |
圖3-1 地址轉換和FIFO頁面調度流程
當產生缺頁中斷後,操作系統總是選擇P[k]所指出的頁面調出,然後執行
P[k]∶=要裝入的新頁頁號
k∶=(k+1)mod m
在實驗中不必實際地啓動磁盤執行調出一頁和裝入一頁的工作,而用輸出“OUT調出的頁號”和“IN要裝入的新頁頁號”來模擬一次調出和裝入的過程。模擬程序的流程見圖3-1。
- 假定主存的每塊長度爲1024個字節,現有一個共7頁的作業,其副本已在磁盤上。系統爲該作業分配了4塊主存塊,且該作業的第0頁至第3頁已經裝入主存,其餘3頁尚未裝入主存,該作業的頁表見表3-2所示。
表3-2 作業的頁表
頁號 |
標誌 |
主存塊號 |
修改標誌 |
在磁盤上的位置 |
0 |
1 |
5 |
0 |
011 |
1 |
1 |
8 |
0 |
012 |
2 |
1 |
9 |
0 |
013 |
3 |
1 |
1 |
0 |
021 |
4 |
0 |
|
0 |
022 |
5 |
0 |
|
0 |
023 |
6 |
0 |
|
0 |
121 |
如果該作業依次執行的指令序列如表3-3所示。
表3-3 作業依次執行的指令序列
操作 |
頁號 |
頁內地址 |
操作 |
頁號 |
頁內地址 |
+ |
0 |
070 |
移位 |
4 |
053 |
+ |
1 |
050 |
+ |
5 |
023 |
× |
2 |
015 |
存 |
1 |
037 |
存 |
3 |
021 |
取 |
2 |
078 |
取 |
0 |
056 |
+ |
4 |
001 |
- |
6 |
040 |
存 |
6 |
084 |
依次執行上述的指令序列來調試你所設計的程序(僅模擬指令的執行,不必考慮指令序列中具體操作的執行)
- 爲了檢查程序的正確性,可自行確定若干組指令序列,運行設計的程序,覈對執行結果。
- 實驗代碼:
#include<iostream>
#include <cstring>
#include<string>
#define NUM 7
#define WNUM 12
using namespace std;
struct pagetable
{
int num;// 頁號
int flag;// 標誌
int block;// 主存塊號
int modify;// 修改標誌
int location;// 磁盤上的位置
};
// 主存塊號是-1 說明該頁沒有調入主存
struct pagetable
page[NUM]={{0,1,5,0,010},{1,1,8,0,012},{2,1,9,0,013},{3,1,1,0,021},{4,0,-1,0,022},{5,0,
-1,0,023},{6,0,-1,0,121}};
struct work
{
char operation[10];// 操作
int pagenum;// 頁號
int address;// 頁內地址
};
struct work w[WNUM]={{"+",0,70},{"+",1,50},{"*",2,15},{" 存",3,21},
{" 取",0,56},{"-",6,40},{" 移位",4,53},{"+",5,23},
{" 存",1,37},{" 取",2,78},{"+",4,1},{" 存",6,84}};
int main()
{
int k=0;// 當要裝入新頁時應調出的頁在數組的位置
int m=4;// 允許分配的最大塊數
int curpage = 0;// 當前頁號
int p[4] = {0,1,2,3};// 當前已在主存中的頁面
int replace;// 替換頁的頁號
int tempflag;
int tempmodify;
long memoryaddress;// 物理地址(絕對地址)
cout<<" 最後的結果是:"<<endl;
printf("\n 操作\t頁號\t頁內地址 標誌 絕對地址 修改頁號 絕對地址 修改標誌\n");
for(int i=0;i<WNUM;i++)
{
curpage = w[i].pagenum;
tempflag = page[curpage].flag;
if(page[curpage].flag == 0)
{
replace = p[k];
p[k] = curpage;
k=(k+1)%m;
page[curpage].flag = 1;
page[curpage].block = page[replace].block;
tempmodify = page[replace].modify;
page[replace].block = -1;
page[replace].flag = 0;
page[replace].modify = 0;
}
memoryaddress = 1024*page[curpage].block+w[i].address;
if(!strcmp(w[i].operation," 存") || !strcmp(w[i].operation," 寫"))
page[curpage].modify=1;
else
page[curpage].modify=0;
printf(" %s\t",w[i].operation);
printf(" %d\t",w[i].pagenum);
printf(" %d\t",w[i].address);
printf(" %d\t",tempflag);
if(tempflag==1)
printf(" %d\t",memoryaddress);
else
printf(" *%d\t",w[i].pagenum);
if(tempflag==1)
printf(" \t");
else
printf(" %d->%d\t",w[i].pagenum,replace);
printf(" %d\t",memoryaddress);
printf(" %d\t",page[curpage].modify);
printf("\n");
}
}
四、實驗結果:
實驗結果截圖如下:
輸入爲:表3-3 作業依次執行的指令序列
操作 |
頁號 |
頁內地址 |
操作 |
頁號 |
頁內地址 |
+ |
0 |
070 |
移位 |
4 |
053 |
+ |
1 |
050 |
+ |
5 |
023 |
× |
2 |
015 |
存 |
1 |
037 |
存 |
3 |
021 |
取 |
2 |
078 |
取 |
0 |
056 |
+ |
4 |
001 |
- |
6 |
040 |
存 |
6 |
084 |
五、心得體會:
C++編程可以模擬實現很多操作系統原理,通過一步步實現其中的原理,可以幫助更好地深入理解操作系統內部構造,將抽象的東西具體化。在實際運行過程,把有關作業的全部信息都裝入主存儲器後,作業執行時實際上不是同時使用全部信息的,有些部分運行一遍便再也不用,甚至有些部分在作業執行的整個過程中都不會被使用到(如錯誤處理部分)。進程在運行時不用的,或暫時不用的,或某種條件下才用的程序和數據,全部駐留於內存中是對寶貴的主存資源的一種浪費,大大降低了主存利用率。
於是,提出了這樣的問題:作業提交時,先全部進入輔助存儲器,作業投入運行時,能否不把作業的全部信息同時裝入主存儲器,而是將其中當前使用部分先裝入主存儲器,其餘暫時不用的部分先存放在作爲主存擴充的輔助存儲器中,待用到這些信息時,再由系統自動把它們裝入到主存儲器中,這就是虛擬存儲器的基本思路。這都是通過編程來解決操作系統中實際遇到的問題,對上課瞭解的知識能給予很好地擴充。