一、實驗目的
多道程序設計中,經常是若干個進程同時處於就緒狀態,必須依照某種策略來決定那個進程優先佔有處理機。因而引起進程調度。本實驗模擬在單處理機情況下的處理機調度問題,加深對進程調度的理解。因爲源碼中我對一些關鍵步驟的註釋已經比較清晰了,所以在本文中不會再對每一個細節都進行分析,只分析整體的代碼結構和所使用到的設計模式。
博客內所有文章均爲 原創,所有示意圖均爲 原創,若轉載請附原文鏈接。
二、實驗內容
2.1 優先權法和輪轉法
- 簡化假設
- 1)進程爲計算型的(無I/O)
- 2)進程狀態:ready、running、finish
- 3)進程需要的CPU時間以時間片爲單位確定
2.2 算法描述
- 1)優先權法——動態優先權
當前運行進程用完時間片後,其優先權減去一個常數。 - 2)輪轉法
三、流程圖
3.1 優先權法
3.2 輪轉法
四、實驗要求
1.產生的各種隨機數的取值範圍加以限制,如所需的CPU時間限制在1~20之間。
2.進程數n不要太大通常取4~8個
3.使用動態數據結構
五、設計思想
5.1 設計思路
在該實驗中需要實現兩種算法,兩種算法的實現思路和流程在流程圖中已經詳細的給出了,需要注意的是在輪轉法中,需要用隨機數產生進程所需要的時間片數(而不是固定值1)。
5.2 代碼解析
因爲兩種算法的本質是一樣的,因此這裏使用了 模板方法設計模式 和 策略模式,其中模板方法設計模式指的是對於優先權法和輪轉法設計一個抽象基類,定義該算法的必要功能接口,然後兩個算法只需要按照自己的算法來實現該功能就可以了,具體的定義情況如下。
/* 調度算法基類 */
class SchedulingAlgorithm
{
public:
virtual bool initPCB(std::priority_queue<PCB, std::vector<PCB>, std::less<PCB>> * ready_queue, int process_num) = 0;
virtual bool processPCB(PCB & pcb) = 0;
};
/* 優先權法(僅定義類簽名,具體代碼實現見下文)*/
class DynamicPrioritySchedulingAlgorithm : public SchedulingAlgorithm;
/* 輪轉法(僅定義類簽名,具體代碼實現見下文)*/
class TimeSliceRotationSchedulingAlgorithm : public SchedulingAlgorithm;
DynamicPrioritySchedulingAlgorithm 是動態優先權算法的實現,在該算法實現的 processPCB 方法中定義了每一輪執行完畢後需要對 PCB 所進行的操作,從而實現動態優先權算法。而在 initPCB 方法中會使用隨機的方式初始化每一個PCB(隨機優先級等)。
class DynamicPrioritySchedulingAlgorithm : public SchedulingAlgorithm
{
public:
bool processPCB(PCB & pcb)
{
pcb.priority -= PRIORITY_DIMINISHING_CONSTANT;
}
bool initPCB(std::priority_queue<PCB, std::vector<PCB>, std::less<PCB>> * ready_queue, int process_num)
{
for (int i = 0; i < process_num; ++i)
{
PCBptr pcb = new PCB();
pcb->pid = i;
pcb->status = Ready;
pcb->time = Util::getRandom(1, 20, i);
pcb->round_trip_time = 1;
pcb->elapsed_time = 0;
// use small intervals to observe changes
pcb->priority = Util::getRandom(1000, 1020, i);
std::cout << "[INFO] init process " << pcb->pid << " with"
<< " status " << pcb->status
<< " need time slices " << pcb->time
<< " priority " << pcb->priority << std::endl;
ready_queue->push(*pcb);
}
std::cout << "[INFO] ready queue init finish." << std::endl;
}
private:
const int PRIORITY_DIMINISHING_CONSTANT = 3;
};
TimeSliceRotationSchedulingAlgorithm 則是時間片輪轉法的實現,在該算法中沒有對執行完的 PCB 做過多的處理,而主要是在 initPCB 方法中隨機產生輪轉時間片數量。
class TimeSliceRotationSchedulingAlgorithm : public SchedulingAlgorithm
{
public:
bool processPCB(PCB & pcb)
{
// do nothing
}
bool initPCB(std::priority_queue<PCB, std::vector<PCB>, std::less<PCB>>* ready_queue, int process_num)
{
for (int i = 0; i < process_num; ++i)
{
PCBptr pcb = new PCB();
pcb->pid = i;
pcb->status = Ready;
pcb->time = Util::getRandom(1, 20, i);
pcb->round_trip_time = Util::getRandom(1, 5, i);
pcb->elapsed_time = 0;
pcb->priority = 0;
std::cout << "[INFO] init process " << pcb->pid << " with"
<< " status " << pcb->status
<< " need time slices " << pcb->time
<< " priority " << pcb->priority
<< " round trip time " << pcb->round_trip_time << std::endl;
ready_queue->push(*pcb);
}
std::cout << "[INFO] ready queue init finish." << std::endl;
}
};
最後,在 ProcessScheduling 類中將不同的算法進行聚合和初始化工作(調用不同算法的 initPCB 方法來初始化 PCB ),並能夠使外部進行調用,定義共同的邏輯,並通過模板函數的方式傳入選擇的算法(策略設計模式),從而通過不同的進程調度算法來執行邏輯,這部分的代碼就不進行剖析了,直接放在下面的代碼實現中。
六、代碼實現
#include <iostream>
#include <vector>
#include <queue>
#include <cstdlib>
#include <ctime>
#include <unistd.h>
class Util
{
public:
static inline int getRandom(const int min_val, const int max_val, int match)
{
srand(time(0) + match);
return rand() % (max_val - min_val - 1) + min_val;
}
};
enum ProcessStatus
{
Ready = 0,
Running = 1,
Finish = 2
};
typedef int Pid;
typedef int TimeSlice;
typedef int Priority;
struct PCB
{
Pid pid;
ProcessStatus status;
TimeSlice time;
TimeSlice round_trip_time;
TimeSlice elapsed_time;
Priority priority;
};
bool operator > (PCB p1, PCB p2) {
return p1.priority > p2.priority;
}
bool operator < (PCB p1, PCB p2) {
return p1.priority < p2.priority;
}
typedef PCB* PCBptr;
class SchedulingAlgorithm
{
public:
virtual bool initPCB(std::priority_queue<PCB, std::vector<PCB>, std::less<PCB>> * ready_queue, int process_num) = 0;
virtual bool processPCB(PCB & pcb) = 0;
};
class DynamicPrioritySchedulingAlgorithm : public SchedulingAlgorithm
{
public:
bool processPCB(PCB & pcb)
{
pcb.priority -= PRIORITY_DIMINISHING_CONSTANT;
}
bool initPCB(std::priority_queue<PCB, std::vector<PCB>, std::less<PCB>> * ready_queue, int process_num)
{
for (int i = 0; i < process_num; ++i)
{
PCBptr pcb = new PCB();
pcb->pid = i;
pcb->status = Ready;
pcb->time = Util::getRandom(1, 20, i);
pcb->round_trip_time = 1;
pcb->elapsed_time = 0;
// use small intervals to observe changes
pcb->priority = Util::getRandom(1000, 1020, i);
std::cout << "[INFO] init process " << pcb->pid << " with"
<< " status " << pcb->status
<< " need time slices " << pcb->time
<< " priority " << pcb->priority << std::endl;
ready_queue->push(*pcb);
}
std::cout << "[INFO] ready queue init finish." << std::endl;
}
private:
const int PRIORITY_DIMINISHING_CONSTANT = 3;
};
class TimeSliceRotationSchedulingAlgorithm : public SchedulingAlgorithm
{
public:
bool processPCB(PCB & pcb)
{
// do nothing
}
bool initPCB(std::priority_queue<PCB, std::vector<PCB>, std::less<PCB>>* ready_queue, int process_num)
{
for (int i = 0; i < process_num; ++i)
{
PCBptr pcb = new PCB();
pcb->pid = i;
pcb->status = Ready;
pcb->time = Util::getRandom(1, 20, i);
pcb->round_trip_time = Util::getRandom(1, 5, i);
pcb->elapsed_time = 0;
pcb->priority = 0;
std::cout << "[INFO] init process " << pcb->pid << " with"
<< " status " << pcb->status
<< " need time slices " << pcb->time
<< " priority " << pcb->priority
<< " round trip time " << pcb->round_trip_time << std::endl;
ready_queue->push(*pcb);
}
std::cout << "[INFO] ready queue init finish." << std::endl;
}
};
template<typename SchedulingAlgorithm>
class ProcessScheduling
{
public:
ProcessScheduling(int pn)
{
process_num_ = pn;
ready_queue_ = new std::priority_queue<PCB, std::vector<PCB>, std::less<PCB>>();
finish_queue_ = new std::queue<PCB>();
sa_ = new SchedulingAlgorithm();
sa_->initPCB(ready_queue_, process_num_);
}
bool destroyFinishQueue()
{
while (!finish_queue_->empty())
{
PCB pcb = finish_queue_->front();
delete &pcb;
finish_queue_->pop();
}
//delete finish_queue_;
return true;
}
bool destroyReadyQueue()
{
while (!ready_queue_->empty())
{
PCB pcb = ready_queue_->top();
delete &pcb;
ready_queue_->pop();
}
delete ready_queue_;
return true;
}
~ProcessScheduling()
{
// delete pcb of ready queue
destroyFinishQueue();
destroyReadyQueue();
delete sa_;
}
bool runProces(PCB & pcb)
{
pcb.status = Running;
std::cout << "[INFO] process " << pcb.pid << " status change to Running." << std::endl;
//std::cout << "[INFO] process " << pcb.pid << " begin run." << std::endl;
// simulation process running
sleep(1);
std::cout << "[INFO] process " << pcb.pid << " end run. " << pcb.time << " more time slices." << std::endl;
if (--pcb.time == 0)
{
std::cout << "[INFO] process " << pcb.pid << " exec finish." << std::endl;
return false;
}
++pcb.elapsed_time;
// return process can continue to running
return true;
}
bool start()
{
while (!ready_queue_->empty())
{
PCB pcb = ready_queue_->top();
ready_queue_->pop();
do {
if (runProces(pcb))
{
if (pcb.round_trip_time != pcb.elapsed_time) continue;
pcb.elapsed_time = 0;
// if the time slice of this process is not used out
// continue to running
pcb.status = Ready;
std::cout << "[INFO] process " << pcb.pid << " status change to Ready." << std::endl;
sa_->processPCB(pcb);
ready_queue_->push(pcb);
}
else
{
pcb.status = Finish;
std::cout << "[INFO] process " << pcb.pid << " status change to Finish." << std::endl;
finish_queue_->push(pcb);
continue;
}
// while pcb.elapsed_time not equal pcb.round_trip_time
} while (pcb.elapsed_time && pcb.status != Finish);
}
std::cout << "[INFO] all process finish exec." << std::endl;
}
void getCurrentReadyQueue()
{
while (!ready_queue_->empty())
{
PCB pcb = ready_queue_->top();
std::cout << pcb.priority << std::endl;
ready_queue_->pop();
}
}
private:
int process_num_;
std::priority_queue<PCB, std::vector<PCB>, std::less<PCB>>* ready_queue_;
std::queue<PCB>* finish_queue_;
SchedulingAlgorithm* sa_;
};
int main()
{
std::cout << "Please input n (process num should between 4-8) and process scheduling algorithm (use space to split)" << std::endl;
std::cout << " (1 means DynamicPrioritySchedulingAlgorithm AND 2 means TimeSliceRotationSchedulingAlgorithm)" << std::endl;
int n = 0, sa = 1;
std::cin >> n >> sa;
if (sa == 1)
{
ProcessScheduling<DynamicPrioritySchedulingAlgorithm> ps(n);
ps.start();
}
else
{
ProcessScheduling<TimeSliceRotationSchedulingAlgorithm> ps(n);
ps.start();
}
// pause to see result.
getchar();
return 0;
}
七、結尾
如果本文描述的內容或使用的代碼存在任何問題,請及時聯繫我或在本篇文章的下面進行評論,我會本着對每一位學技術同學的負責態度立即修改。在後續還會有三篇計算機操作系統的算法 C++ 復現博文,如果感興趣可以關注我。