1. 程式人生 > >模擬實現作業系統排程演算法

模擬實現作業系統排程演算法

  之前學習作業系統的時候對作業系統的一些排程演算法比較感興趣,所以自己模擬實現了一下作業系統演算法的排程,我主要模擬實現了短作業優先和先來先服務排程演算法。程式碼有點長,加上測試程式碼估計有300行左右吧,放在這裡的話看起來也不方便(算了,還是放在下面吧,免得看的人覺得麻煩)。我先把實現的結果截圖放在下面吧,然後再附上程式碼,其實在我的github上面也有這些程式碼的,地址: https://github.com/admin-zou/DS/tree/master/scheduling




標頭檔案: //scheduling.h

#ifndef _SCHEDULING_
#define _SCHEDULING_

#include <iostream>
#include <stdlib.h>
using namespace std;

enum Tag{UNSHD,SHD}; //標記是否被排程過

struct PCB
{
	int      pcbid;			//程序號
	size_t  arrtime;			//到達時間
	size_t  sertime;			//服務時間
	size_t  begtime;			//開始時間
	size_t  endtime;			//完成時間
	size_t  turntime;		//週轉時間
	float    weighttime;		//帶權週轉時間
	PCB *   next;			//指向下個節點的指標
	Tag     tag;				//標記是否被排程過
	
	PCB(int n=0,size_t a=0,size_t s=0)
		:pcbid(n),arrtime(a),sertime(s),begtime(0),endtime(0)
		,turntime(0),weighttime(0),next(NULL),tag(UNSHD)
	{}
};

class scheduling
{
public:
	scheduling():_curtime(0),_tasknum(0)
	{
		_head = new PCB();
	}

/////先來先服務演算法
	void FIFS()
	{
		if(empty())
		{
			cout<<"沒有任務";
			exit(-1);
		}
		_clear();  //清理一下,可重複計算
		_sort_t(); //按到達時間排序
		PCB* cur = _head->next;
		while(NULL != cur)
		{
			if(_curtime < cur->arrtime)
			{ 
				_curtime = cur->arrtime; 
			}
			cur->begtime = _curtime; 
			cur->endtime = _curtime + cur->sertime;		//完成時間等於開始時間加服務時間
			cur->turntime = cur->endtime - cur->arrtime;	 //週轉時間=完成時間-到達時間
			cur->weighttime  = (float)cur->turntime / (float)cur->sertime;  //帶權週轉時間=週轉時間/服務時間
			cur->tag = SHD; //標記為已經服務
			_curtime += cur->sertime;
			cur = cur->next;
		}
	}

/////短作業

	void Short()
	{
		if (empty())
		{
			cout << "沒有任務";
			exit(-1);
		}
		_clear();  //清理一下,可重複計算
		_sort_t(); //按到達時間排序
		
		PCB* cur = _head->next;
		while (NULL != cur)
		{
			if (_curtime < cur->arrtime)
			{
				_curtime = cur->arrtime;
			}
			cur->begtime = _curtime;
			cur->endtime = _curtime + cur->sertime;		//完成時間等於開始時間加服務時間
			cur->turntime = cur->endtime - cur->arrtime;	 //週轉時間=完成時間-到達時間
			cur->weighttime = (float)cur->turntime / (float)cur->sertime; //帶權週轉時間=週轉時間/服務時間
			cur->tag = SHD; //標記為已經服務
			_curtime += cur->sertime;
			cur = cur->next;
		
			//將該程序排程完的時刻已經到達的程序按短作業優先排序	
			_sort_l(cur,_curtime);  //從該程序開始進行短作業排序

		}
	}

	void Init_task()
	{
		int tasknum=0;
		size_t id=0;
		size_t atime=0;
		size_t stime=0;
		cout<<"請輸入任務的個數:";
		cin>>tasknum;	
		for(int i = 0; i<tasknum;i++)
		{
			cout<<"請分別輸入任務的編號,到達時間,執行時間:";
			cin>>id>>atime>>stime;
			push(id,atime,stime);
		}
	}

	void Push()
	{	
		size_t id=0;
		size_t atime=0;
		size_t stime=0;
		cout<<"請分別輸入任務的編號,到達時間,執行時間:";
		cin>>id>>atime>>stime;
		push(id,atime,stime);
	}
	
	void Print()
	{
		if(empty())
			return ;
		PCB* cur = _head->next;
		printf("程序號 到達時間 服務時間 開始時間 完成時間 週轉時間 帶權週轉時間 \n");
		while(NULL != cur)
		{
			printf("%4d %6d %8d %9d %7d  %8d\t %0.2f\n",cur->pcbid, cur->arrtime ,cur->sertime ,cur->begtime, cur->endtime ,cur->turntime ,cur->weighttime);
			cur = cur->next;
		}
	}

	
protected:
	bool empty()
	{
		return _tasknum == 0;
	}
	
	bool push(int n,size_t a,size_t s) //插入到連結串列尾部
	{
		PCB * newtask = new PCB(n,a,s);
		PCB * cur = _head;
		while(NULL != cur->next)
			cur =cur->next;
		cur->next=newtask;
		_tasknum++;
		return true;
	}
	
	void _clear()
	{
		if(empty())
			return ;
		PCB* cur = _head->next;
		while(NULL != cur)
		{
			cur->begtime = 0;
			cur->endtime = 0;
			cur->turntime = 0;
			cur->weighttime = 0;
			cur->tag = UNSHD;
			cur = cur->next ;
		}
		_curtime = 0;
	}

// 按照到達時間排序
	void _sort_t() 
	{
		if(empty() || _tasknum == 1)
			return;
		PCB* prev = _head->next;
		PCB* cur = prev->next;
		for(int i = 0; i< _tasknum-1; i++)
		{
			for(int j = 0; j<_tasknum-i-1; j++)
			{
				if (prev->arrtime > cur->arrtime)
				{
					_Swap(prev, cur);
				}
				prev = cur;
				cur = cur->next;
			}
			prev=_head->next;
			cur = prev->next;
		}
	}

// 按照作業長短排序
	void _sort_l(PCB*& head,size_t curtime)
	{
		if (NULL == head || NULL == head->next)
			return;
		PCB* prev = head;
		PCB* cur = prev->next;
		int size = 0;  //計算程序的數目
		PCB* tmp = head;
		while (tmp)
		{
			++size;
			tmp = tmp->next;
		}

		for (int i = 0; cur->arrtime < curtime && i < size - 1; i++)
		{
			if (prev->arrtime > curtime)
			{//作業還沒到達就不排序
				return;
			}
			for (int j = 0; j < size - i - 1; j++)
			{
				if (cur && cur->arrtime <= curtime)
				{
					int ptime = prev->sertime;
					int ctime = cur->sertime;
					if (ptime > ctime)
					{
						_Swap(prev, cur);
					}
				}
				prev = cur;
				cur = cur->next;
			}
			prev = head;
			cur = prev->next;
		}
	}

	void _Swap(PCB * prev,PCB * cur)
	{
		swap(prev->arrtime,cur->arrtime);
		swap(prev->pcbid ,cur->pcbid );
		swap(prev->sertime ,cur->sertime );
	}

private:
	PCB *	_head;
	size_t  _curtime;	
	size_t  _tasknum;	//作業個數
};

#endif

測試檔案:
#define	_CRT_NOWANRINGS
#include"scheduling.h"

int main()
{
	int select=1;
	scheduling mytask;
	while(select)
	{
		cout<<"****************************"<<endl;
		cout<<"*   1.初始化               *"<<endl;
		cout<<"*   2.新插入一個程序       *"<<endl;
		cout<<"*   3.先來先服務排程演算法   *"<<endl;
		cout<<"*   4.短作業排程演算法       *"<<endl;
		cout<<"*   5.顯示排程情況         *"<<endl;
		cout<<"*   0.退出                 *"<<endl;
		cout<<"****************************"<<endl;
		int item=0;
		cout<<"請輸入:";
		cin>>select;
		switch(select)
		{
		case 1:
			mytask.Init_task();		
			break;
		case 2:
			mytask.Push();
			break;
		case 3:
			mytask.FIFS();
			break;
        case 4:
			mytask.Short();
			break;
		case 5:
			mytask.Print();
			cout << endl;
			break;
		default:
			break;
		}
	}
	return 0;
}

//測試條件
/*
5
1 0 4
2 2 4
3 3 3
4 5 6
5 6 3
*/

   總結:

       1.上面的程式基於是我對作業系統排程演算法的理解所寫出來的,主要模擬了先來先服務和短作業優先排程兩種排程演算法,其中涉及到了c++,資料結構以及作業系統和演算法等方面的只是,實現它確實大有所益。

       2.在上面的小專案中我是通過計算出各種排程演算法的週轉時間,帶權週轉時間等等來評價排程演算法的效率的,能夠在一定範圍內評估排程演算法的效能,以及某些場景適合於使用哪種排程演算法。

      3.我是通過單鏈表來組織相關的作業的排程需要的資料的,這樣確實有好處,也有缺陷,這和連結串列的優缺點相對應。不過在資料量較小的時候還是很不錯的。

    其中主要的難點在於很難分析出所有可能出現的情況,以及各種情況下的行為。還有就是,需要對作業系統的排程演算法有一定的理解,否則就容易出現於實際不符的結果,比如說短作業優先排程,怎樣理解這種排程方式呢,我舉個例子吧:一開始時只有一個作業在排程,但是其所需時間比較長,在他執行過程中來了其他作業,但是作業時間很短,先排程這個短作業可能會更優,那麼我們需要怎麼處理呢,這就涉及到了是否允許搶佔資源的問題(當然在我的實現中是不可搶佔資源的)。最後說明一下在開發的時候一定要多除錯,減少bug,增加程式的健壯性。