운영체제에서 CPU Scheduler는 여러 프로세스의 상황을 고려하여 CPU와 시스템 자원의 배정을 결정한다.
CPU Scheduler는 다양한 스케줄링 알고리즘으로 다음 프로세스를 선택하는데, 이 알고리즘들을 C++을 사용해서 구현해보았다.
Process.h에 Process 클래스를 선언하여 PID, 도착 시간, 실행 시간, 대기 시간, 반환 시간, 우선 순위 등 각 프로세스에 대한 정보들을 저장하는 클래스 구현
#ifndef PROCESS_H
#define PROCESS_H
#include <iostream>
#include <queue>
using namespace std;
class Process
{
public:
int id;
int arrivalTime; //도착 시간
int executionTime; //실행 시간
int waitingTime; //대기 시간
int returnTime; //반환 시간
double priority; //우선 순위
int startTime; //시작 시간
int runningTime; //현재 실행 시간(진행도)
int status; // 프로세스의 상태(-1이면 생성, 0이면 대기, 1이면 실행중, 2이면 완료)
Process(int id, int arrivalTime, int executionTime)
{
this->id = id;
this->arrivalTime = arrivalTime;
this->executionTime = executionTime;
this->priority = 0.0;
this->status = -1;
}
Process(int id, int arrivalTime, int executionTime, int priority)
{
this->id = id;
this->arrivalTime = arrivalTime;
this->executionTime = executionTime;
this->priority = priority;
this->status = -1;
}
void start(int currentTime) // 프로세스 시작
{
//cout << "Time=" << currentTime << " PID " << id << " Start\n"; //프로세스 실행 로그
status = 1;
}
void pause(int currentTime) // 프로세스 중지(Context Switch)
{
status = 0;
}
void finish(int currentTime) // 프로세스 종료
{
//cout << "Time=" << currentTime << " PID " << id << " Finish\n"; //프로세스 종료 로그
status = 2;
returnTime = waitingTime + executionTime; // 반환 시간 = 대기 시간 + 실행 시간
}
};
#endif
ProcessUtil.cpp에 우선순위 큐를 정렬하는 기준들과 대기 시간 추가, 우선순위 큐의 데이터 변경에 따른 큐 업데이트 함수를 구현하였다.
#include "Process.h"
struct BurstTimeComparator // 실행 시간 우선 순위 큐 정렬
{
bool operator()(const Process *a, const Process *b)
{
return a->executionTime > b->executionTime; // 실행 시간이 짧은 프로세스부터 정렬
}
};
struct PriorityComparator // 우선 순위 큐 정렬
{
bool operator()(const Process *a, const Process *b)
{
if (a->priority == b->priority) // 우선순위가 같을 때
return a->arrivalTime > b->arrivalTime; // 먼저 도착한 프로세스가 앞으로 정렬(FIFO)
return a->priority > b->priority; // 우선순위 높은(숫자가 작은) 순서로 정렬
}
};
struct RemainTimeComparator // 남은 실행 시간 우선 순위 큐 정렬
{
bool operator()(const Process *a, const Process *b)
{
if (a->executionTime - a->runningTime == b->priority - b->runningTime) // 우선순위가 같을 때
return a->arrivalTime > b->arrivalTime; // 먼저 도착한 프로세스가 앞으로 정렬(FIFO)
return a->executionTime - a->runningTime > b->executionTime - b->runningTime; // 남은 실행시간이 작은 순서로 정렬
}
};
void update_waitingTime(vector<Process *> &process)
{
for(int i = 0;i<process.size();i++)
if(process[i]->status == 0) {
process[i]->waitingTime++;
}
}
template <typename T>
void update_queue(priority_queue<Process *, vector<Process *>, T> &pq)
{
int len = pq.size();
while (len--)
{
Process *temp = pq.top();
temp->priority = double(temp->executionTime) / (temp->waitingTime + temp->executionTime);
pq.push(temp);
pq.pop();
}
}
FCFS 스케줄링 알고리즘은 프로세스가 생성되어 레디 큐에 들어온 순서대로 프로세스를 처리하기 때문에 큐 자료구조를 사용했다.
#include "ProcessUtil.cpp"
#include <queue>
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
vector<int> timeHistory; // 간트 차트를 그리기 위한 타임 라인
Process *p;
vector<Process *> process;
queue<Process *> q; // Ready queue
ifstream fin("Processes.txt");
if (!fin.is_open())
{
cout << "File open failed...\n";
return 1;
}
while (!fin.eof())
{
int id = 0;
int arrivalTime = 0;
int executionTime = 0;
int priority = 0;
fin >> id >> arrivalTime >> executionTime >> priority;
p = new Process(id, arrivalTime, executionTime); // 새로운 프로세스 생성
process.push_back(p);
}
int currentTime = 0; // 현재 시간
int processCount = 0; // 프로세스가 도착한 순서대로 큐에 들어갈 때 인덱스
Process *runningProcess = NULL; // 실행 중인 프로세스
bool isRunningExists = false; // 실행중인 프로세스가 있는지
cout << "\n";
while (1)
{
if (process.size() > processCount && currentTime == process[processCount]->arrivalTime) // 현재 시간이 다음 프로세스 도착 시간일 때
{
// cout << "Time=" << currentTime << " PID " << process[processCount]->id << " Arrive\n"; // 프로세스 도착 로그
process[processCount]->status = 0;
q.push(process[processCount++]);
}
if (!isRunningExists) // 현재 실행중인 프로세스가 없을 때
{
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess = q.front(); // 다음 프로세스 선택
q.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
cout << "|P" << runningProcess->id;
}
if (runningProcess->runningTime == runningProcess->executionTime) // 프로세스가 작업을 완료하고 종료될 때
{
cout << "|";
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess->finish(currentTime); // 프로세스 종료
isRunningExists = false;
if (q.empty()) // 모든 프로세스 종료 시
{
break;
}
runningProcess = q.front(); // 다음 프로세스 선택
q.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
cout << "P" << runningProcess->id;
}
cout << "-";
runningProcess->runningTime++;
currentTime++; // 시간 진행
update_waitingTime(process); // 대기 중인 프로세스 대기 시간 추가
}
// 타임 라인 출력
cout << "\n";
int historyCount = 0;
for (int i = 0; i <= currentTime; i++)
{
if (i == timeHistory[historyCount])
{
if (i != 0)
{
if(i < 10) {
cout << " ";
}
cout << " ";
}
cout << timeHistory[historyCount++];
}
else
{
cout << " ";
}
}
cout << "\n\n";
double sumWaitingTime = 0;
double sumReturnTime = 0;
for (int i = 0; i < process.size(); i++)
{
cout << "PID " << process[i]->id << " Waiting Time = " << process[i]->waitingTime << " Return Time = " << process[i]->returnTime << "\n";
sumWaitingTime += process[i]->waitingTime;
sumReturnTime += process[i]->returnTime;
}
cout << "Average Waiting Time = " << sumWaitingTime / process.size() << "\n";
cout << "Average Return Time = " << sumReturnTime / process.size() << "\n";
delete[] p;
fin.close();
return 0;
}
SJF 알고리즘은 실행 시간이 짧은 프로세스 먼저 실행시켜야 하기 때문에 실행 시간을 우선순위로 이용한 우선순위 큐 자료구조를 사용하였다.
위 코드와 같이 실행 시간이 짧은 프로세스가 먼저 pop 될 수 있도록 정렬하였다.
#include "Process.h"
#include "ProcessUtil.cpp"
#include <queue>
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
vector<int> timeHistory; // 간트 차트를 그리기 위한 타임 라인
Process *p;
vector<Process *> process;
priority_queue<Process *, vector<Process *>, BurstTimeComparator> pq; // Ready queue
ifstream fin("Processes.txt");
if (!fin.is_open())
{
cout << "File open failed...\n";
return 1;
}
while (!fin.eof())
{
int arrivalTime = 0;
int executionTime = 0;
int priority = 0;
fin >> id >> arrivalTime >> executionTime >> priority;
p = new Process(id, arrivalTime, executionTime);
process.push_back(p);
}
int currentTime = 0; // 현재 시간
int processCount = 0; // 프로세스가 도착한 순서대로 큐에 들어갈 때 인덱스
Process *runningProcess = NULL; // 실행 중인 프로세스
bool isRunningExists = false; // 실행중인 프로세스가 있는지
cout << "\n";
while (1)
{
if (process.size() > processCount && currentTime == process[processCount]->arrivalTime) // 현재 시간이 다음 프로세스 도착 시간일 때
{
// cout << "Time=" << currentTime << " PID " << process[processCount]->id << " Arrive\n"; // 프로세스 도착 로그
process[processCount]->status = 0;
pq.push(process[processCount++]);
}
if (!isRunningExists) // 현재 실행중인 프로세스가 없을 때
{
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess = pq.top(); // 다음 프로세스 선택
pq.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
cout << "|P" << runningProcess->id;
}
if (runningProcess->runningTime == runningProcess->executionTime) // 프로세스가 작업을 완료하고 종료될 때
{
cout << "|";
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess->finish(currentTime); // 프로세스 종료
isRunningExists = false;
if (pq.empty()) // 모든 프로세스 종료 시
{
break;
}
runningProcess = pq.top(); // 다음 프로세스 선택
pq.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
cout << "P" << runningProcess->id;
}
cout << "-";
runningProcess->runningTime++;
currentTime++; // 시간 진행
update_waitingTime(process); // 대기 중인 프로세스 대기 시간 추가
}
// 타임 라인 출력
cout << "\n";
int historyCount = 0;
for (int i = 0; i <= currentTime; i++)
{
if (i == timeHistory[historyCount])
{
if (i != 0)
{
if(i < 10) {
cout << " ";
}
cout << " ";
}
cout << timeHistory[historyCount++];
}
else
{
cout << " ";
}
}
cout << "\n\n";
double sumWaitingTime = 0;
double sumReturnTime = 0;
for (int i = 0; i < process.size(); i++)
{
cout << "PID " << process[i]->id << " Waiting Time=" << process[i]->waitingTime << " Return Time=" << process[i]->returnTime << "\n";
sumWaitingTime += process[i]->waitingTime;
sumReturnTime += process[i]->returnTime;
}
cout << "Average Waiting Time = " << sumWaitingTime / process.size() << "\n";
cout << "Average Return Time = " << sumReturnTime / process.size() << "\n";
delete[] p;
fin.close();
return 0;
}
우선순위가 높은(숫자가 작은) 프로세스 순서대로 실행되어야 하기 때문에 우선순위 큐 자료구조를 사용하였다.
#include "Process.h"
#include "ProcessUtil.cpp"
#include <queue>
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
vector<int> timeHistory; // 간트 차트를 그리기 위한 타임 라인
Process *p;
vector<Process *> process;
priority_queue<Process *, vector<Process *>, PriorityComparator> pq; // Ready queue
ifstream fin("Processes.txt");
if (!fin.is_open())
{
cout << "File open failed...\n";
return 1;
}
while (!fin.eof())
{
int id = 0;
int arrivalTime = 0;
int executionTime = 0;
int priority = 0;
fin >> id >> arrivalTime >> executionTime >> priority;
p = new Process(id, arrivalTime, executionTime, priority);
process.push_back(p);
}
int currentTime = 0; // 현재 시간
int processCount = 0; // 프로세스가 도착한 순서대로 큐에 들어갈 때 인덱스
Process *runningProcess = NULL; // 실행 중인 프로세스
bool isRunningExists = false; // 실행중인 프로세스가 있는지
cout << "\n";
while (1)
{
if (process.size() > processCount && currentTime == process[processCount]->arrivalTime) // 현재 시간이 다음 프로세스 도착 시간일 때
{
// cout << "Time=" << currentTime << " PID " << process[processCount]->id << " Arrive\n"; // 프로세스 도착 로그
process[processCount]->status = 0;
pq.push(process[processCount++]);
}
if (!isRunningExists) // 현재 실행중인 프로세스가 없을 때
{
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess = pq.top(); // 다음 프로세스 선택
pq.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
cout << "|P" << runningProcess->id;
}
if (runningProcess->runningTime == runningProcess->executionTime) // 프로세스가 작업을 완료하고 종료될 때
{
cout << "|";
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess->finish(currentTime); // 프로세스 종료
isRunningExists = false;
if (pq.empty()) // 모든 프로세스 종료 시
break;
runningProcess = pq.top(); // 다음 프로세스 선택
pq.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
cout << "P" << runningProcess->id;
}
cout << "-";
currentTime++; // 시간 진행
runningProcess->runningTime++;
update_waitingTime(process);
}
// 타임 라인 출력
cout << "\n";
int historyCount = 0;
for (int i = 0; i <= currentTime; i++)
{
if (i == timeHistory[historyCount])
{
if (i != 0)
{
if(i < 10)
cout << " ";
cout << " ";
}
cout << timeHistory[historyCount++];
}
else
cout << " ";
}
cout << "\n\n";
double sumWaitingTime = 0;
double sumReturnTime = 0;
for (int i = 0; i < process.size(); i++)
{
cout << "PID " << process[i]->id << " Waiting Time = " << process[i]->waitingTime << " Return Time = " << process[i]->returnTime << "\n";
sumWaitingTime += process[i]->waitingTime;
sumReturnTime += process[i]->returnTime;
}
cout << "Average Waiting Time = " << sumWaitingTime / process.size() << "\n";
cout << "Average Return Time = " << sumReturnTime / process.size() << "\n";
delete[] p;
fin.close();
return 0;
}
비선점형과 다르게 프로세스가 실행되고 있어도 실행 중인 프로세스보다 레디 큐에 들어 있는 프로세스의 우선순위가 더 높으면 바로 Context switch(문맥 교환)이 일어나야 하기 때문에 우선순위 큐 자료구조를 사용하였다.
#include "Process.h"
#include "ProcessUtil.cpp"
#include <queue>
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
vector<int> timeHistory; // 간트 차트를 그리기 위한 타임 라인
Process *p;
vector<Process *> process;
priority_queue<Process *, vector<Process *>, PriorityComparator> pq; // Ready queue
ifstream fin("Processes.txt");
if (!fin.is_open())
{
cout << "File open failed...\n";
return 1;
}
while (!fin.eof())
{
int id = 0;
int arrivalTime = 0;
int executionTime = 0;
int priority = 0;
fin >> id >> arrivalTime >> executionTime >> priority;
p = new Process(id, arrivalTime, executionTime, priority);
process.push_back(p);
}
int currentTime = 0; // 현재 시간
int processCount = 0; // 프로세스가 도착한 순서대로 큐에 들어갈 때 인덱스
Process *runningProcess = NULL; // 실행 중인 프로세스
bool isRunningExists = false; // 실행중인 프로세스가 있는지
cout << "\n";
while (1)
{
if (process.size() > processCount && currentTime == process[processCount]->arrivalTime) // 현재 시간이 다음 프로세스 도착 시간일 때
{
// cout << "Time=" << currentTime << " PID " << process[processCount]->id << " Arrive\n"; // 프로세스 도착 로그
process[processCount]->status = 0;
pq.push(process[processCount++]);
}
if (!isRunningExists) // 현재 실행중인 프로세스가 없을 때
{
runningProcess = pq.top(); // 다음 프로세스 선택
pq.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
timeHistory.push_back(currentTime); // 타임 라인 찍기
cout << "|P" << runningProcess->id;
}
if (pq.top()->priority < runningProcess->priority) // 실행 중인 프로세스의 우선순위보다 큐에 들어있는 프로세스의 우선순위가 높을 때 Context switching
{
cout << "|";
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess->pause(currentTime); // 실행 중인 프로세스 중지
isRunningExists = false;
pq.push(runningProcess); // 큐에 다시 넣기
runningProcess = pq.top(); // 우선순위가 더 높은 프로세스 선택
pq.pop(); // 우선순위가 더 높은 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
cout << "P" << runningProcess->id;
}
if (runningProcess->executionTime == runningProcess->runningTime) // 프로세스가 작업을 완료하고 종료될 때
{
cout << "|";
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess->finish(currentTime); // 프로세스 종료
isRunningExists = false;
if (pq.empty()) // 모든 프로세스 종료 시
{
break;
}
runningProcess = pq.top(); // 다음 프로세스 선택
pq.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
cout << "P" << runningProcess->id;
}
cout << "-";
currentTime++; // 시간 진행
runningProcess->runningTime++;
update_waitingTime(process);
}
// 타임 라인 출력
cout << "\n";
int historyCount = 0;
for (int i = 0; i <= currentTime; i++)
{
if (i == timeHistory[historyCount])
{
if (i != 0)
{
if(i < 10) {
cout << " ";
}
cout << " ";
}
cout << timeHistory[historyCount++];
}
else
{
cout << " ";
}
}
cout << "\n\n";
double sumWaitingTime = 0;
double sumReturnTime = 0;
for (int i = 0; i < process.size(); i++)
{
cout << "PID " << process[i]->id << " Waiting Time = " << process[i]->waitingTime << " Return Time = " << process[i]->returnTime << "\n";
sumWaitingTime += process[i]->waitingTime;
sumReturnTime += process[i]->returnTime;
}
cout << "Average Waiting Time = " << sumWaitingTime / process.size() << "\n";
cout << "Average Return Time = " << sumReturnTime / process.size() << "\n";
delete[] p;
fin.close();
return 0;
}
대기 시간과 사용 시간을 고려하여 스케줄링해야 하기 때문에 우선순위가 실시간으로 변경되어야 한다. 이를 위해 우선순위 큐를 사용하였는데, C++ STL에서 지원하는 우선순위 큐는 데이터를 실시간으로 정렬해주는 기능이 없기 때문에 큐에 있는 모든 데이터를 pop하고 우선순위를 업데이트 시켜준 뒤, 다시 push하는 방법으로 구현하였다.
#include "Process.h"
#include "ProcessUtil.cpp"
#include <queue>
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
vector<int> timeHistory; // 간트 차트를 그리기 위한 타임 라인
Process *p;
vector<Process *> process;
priority_queue<Process *, vector<Process *>, PriorityComparator> pq; // Ready queue
ifstream fin("Processes.txt");
if (!fin.is_open())
{
cout << "File open failed...\n";
return 1;
}
while (!fin.eof())
{
int id = 0;
int arrivalTime = 0;
int executionTime = 0;
int priority = 0;
fin >> id >> arrivalTime >> executionTime >> priority;
p = new Process(id, arrivalTime, executionTime);
process.push_back(p);
}
int currentTime = 0; // 현재 시간
int processCount = 0; // 프로세스가 도착한 순서대로 큐에 들어갈 때 인덱스
Process *runningProcess = NULL; // 실행 중인 프로세스
bool isRunningExists = false; // 실행중인 프로세스가 있는지
cout << "\n";
while (1)
{
if (process.size() > processCount && currentTime == process[processCount]->arrivalTime) // 현재 시간이 다음 프로세스 도착 시간일 때
{
// cout << "Time=" << currentTime << " PID " << process[processCount]->id << " Arrive\n"; // 프로세스 도착 로그
pq.push(process[processCount]);
process[processCount++]->status = 0;
}
if (!isRunningExists) // 현재 실행중인 프로세스가 없을 때
{
runningProcess = pq.top(); // 다음 프로세스 선택
pq.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
timeHistory.push_back(currentTime); // 타임 라인 찍기
cout << "|P" << runningProcess->id;
}
if (runningProcess->runningTime == runningProcess->executionTime) // 프로세스가 작업을 완료하고 종료될 때
{
cout << "|";
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess->finish(currentTime); // 프로세스 종료
isRunningExists = false;
if (pq.empty()) // 모든 프로세스 종료 시
{
break;
}
runningProcess = pq.top(); // 다음 프로세스 선택
pq.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
cout << "P" << runningProcess->id;
}
cout << "-";
currentTime++; // 시간 진행
runningProcess->runningTime++;
update_waitingTime(process);
update_queue(pq);
}
// 타임 라인 출력
cout << "\n";
int historyCount = 0;
for (int i = 0; i <= currentTime; i++)
{
if (i == timeHistory[historyCount])
{
if (i != 0)
{
if (i < 10)
{
cout << " ";
}
cout << " ";
}
cout << timeHistory[historyCount++];
}
else
{
cout << " ";
}
}
cout << "\n\n";
double sumWaitingTime = 0;
double sumReturnTime = 0;
for (int i = 0; i < process.size(); i++)
{
cout << "PID " << process[i]->id << " Waiting Time = " << process[i]->waitingTime << " Return Time = " << process[i]->returnTime << "\n";
sumWaitingTime += process[i]->waitingTime;
sumReturnTime += process[i]->returnTime;
}
cout << "Average Waiting Time = " << sumWaitingTime / process.size() << "\n";
cout << "Average Return Time = " << sumReturnTime / process.size() << "\n";
delete[] p;
fin.close();
return 0;
}
프로세스가 레디 큐에 들어온 순서대로 일정한 타임 슬라이스 동안만 프로세스를 실행하고 타임 아웃이 되면 문맥 교환이 일어나야 한다. 타임 슬라이스는 2로 설정하였으며 사용한 자료구조는 큐이다.
#include "Process.h"
#include "ProcessUtil.cpp"
#include <iostream>
#include <queue>
#include <fstream>
#define TIME_QUANTUM 2
using namespace std;
int main()
{
vector<int> timeHistory; // 간트 차트를 그리기 위한 타임 라인
Process *p;
vector<Process *> process;
queue<Process *> q; // Ready queue
ifstream fin("Processes.txt");
if (!fin.is_open())
{
cout << "File open failed...\n";
return 1;
}
while (!fin.eof())
{
int id = 0;
int arrivalTime = 0;
int executionTime = 0;
int priority = 0;
fin >> id >> arrivalTime >> executionTime >> priority;
p = new Process(id, arrivalTime, executionTime);
process.push_back(p);
}
int currentTime = 0; // 현재 시간
int processCount = 0; // 프로세스가 도착한 순서대로 큐에 들어갈 때 인덱스
Process *runningProcess = NULL; // 실행 중인 프로세스
bool isRunningExists = false; // 실행중인 프로세스가 있는지
int TimeQuantumCount = 0;
cout << "\n";
while (1)
{
if (process.size() > processCount && currentTime == process[processCount]->arrivalTime) // 현재 시간이 다음 프로세스 도착 시간일 때
{
// cout << "Time=" << currentTime << " PID " << process[processCount]->id << " Arrive\n"; // 프로세스 도착 로그
q.push(process[processCount]);
process[processCount++]->status = 0;
}
if (!isRunningExists) // 현재 실행중인 프로세스가 없을 때
{
runningProcess = q.front(); // 다음 프로세스 선택
q.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
timeHistory.push_back(currentTime); // 타임 라인 찍기
cout << "|P" << runningProcess->id;
}
if (runningProcess->runningTime == runningProcess->executionTime) // 프로세스가 작업을 완료하고 종료될 때
{
cout << "|";
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess->finish(currentTime); // 프로세스 종료
isRunningExists = false;
if (q.empty()) // 모든 프로세스 종료 시
{
break;
}
runningProcess = q.front(); // 다음 프로세스 선택
q.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
TimeQuantumCount = 0;
cout << "P" << runningProcess->id;
}
if (TimeQuantumCount == TIME_QUANTUM) // 타임 아웃
{
cout << "|";
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess->pause(currentTime); // 실행 중인 프로세스 중지
isRunningExists = false;
q.push(runningProcess); // 큐에 다시 넣기
runningProcess = q.front(); // 다음 프로세스 선택
q.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
TimeQuantumCount = 0;
cout << "P" << runningProcess->id;
}
cout << "-";
TimeQuantumCount++;
runningProcess->runningTime++;
currentTime++; // 시간 진행
update_waitingTime(process);
}
// 타임 라인 출력
cout << "\n";
int historyCount = 0;
for (int i = 0; i <= currentTime; i++)
{
if (i == timeHistory[historyCount])
{
if (i != 0)
{
if (i < 10)
{
cout << " ";
}
cout << " ";
}
cout << timeHistory[historyCount++];
}
else
{
cout << " ";
}
}
cout << "\n\n";
double sumWaitingTime = 0;
double sumReturnTime = 0;
for (int i = 0; i < process.size(); i++)
{
cout << "PID " << process[i]->id << " Waiting Time = " << process[i]->waitingTime << " Return Time = " << process[i]->returnTime << "\n";
sumWaitingTime += process[i]->waitingTime;
sumReturnTime += process[i]->returnTime;
}
cout << "Average Waiting Time = " << sumWaitingTime / process.size() << "\n";
cout << "Average Return Time = " << sumReturnTime / process.size() << "\n";
delete[] p;
fin.close();
return 0;
}
#include "Process.h"
#include "ProcessUtil.cpp"
#include <queue>
#include <iostream>
#include <fstream>
#include <vector>
#define TIME_QUANTUM 2
using namespace std;
int main()
{
vector<int> timeHistory; // 간트 차트를 그리기 위한 타임 라인
Process *p;
vector<Process *> process;
priority_queue<Process *, vector<Process *>, RemainTimeComparator> pq; // Ready queue
ifstream fin("Processes.txt");
if (!fin.is_open())
{
cout << "File open failed...\n";
return 1;
}
while (!fin.eof())
{
int id = 0;
int arrivalTime = 0;
int executionTime = 0;
int priority = 0;
fin >> id >> arrivalTime >> executionTime >> priority;
p = new Process(id, arrivalTime, executionTime);
process.push_back(p);
}
int currentTime = 0; // 현재 시간
int processCount = 0; // 프로세스가 도착한 순서대로 큐에 들어갈 때 인덱스
Process *runningProcess = NULL; // 실행 중인 프로세스
bool isRunningExists = false; // 실행중인 프로세스가 있는지
int TimeQuantumCount = 0;
cout << "\n";
while (1)
{
if (process.size() > processCount && currentTime == process[processCount]->arrivalTime) // 현재 시간이 다음 프로세스 도착 시간일 때
{
// cout << "Time=" << currentTime << " PID " << process[processCount]->id << " Arrive\n"; // 프로세스 도착 로그
pq.push(process[processCount]);
process[processCount++]->status = 0;
}
if (!isRunningExists) // 현재 실행중인 프로세스가 없을 때
{
runningProcess = pq.top(); // 다음 프로세스 선택
pq.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
timeHistory.push_back(currentTime); // 타임 라인 찍기
cout << "|P" << runningProcess->id;
}
if (runningProcess->runningTime == runningProcess->executionTime) // 프로세스가 작업을 완료하고 종료될 때
{
cout << "|";
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess->finish(currentTime); // 프로세스 종료
isRunningExists = false;
if (pq.empty()) // 모든 프로세스 종료 시
{
break;
}
runningProcess = pq.top(); // 다음 프로세스 선택
pq.pop(); // 다음 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
TimeQuantumCount = 0;
cout << "P" << runningProcess->id;
}
if (TimeQuantumCount == TIME_QUANTUM) // 타임 아웃
{
cout << "|";
timeHistory.push_back(currentTime); // 타임 라인 찍기
runningProcess->pause(currentTime); // 실행 중인 프로세스 중지
isRunningExists = false;
pq.push(runningProcess); // 큐에 다시 넣기
runningProcess = pq.top(); // 우선순위가 더 높은 프로세스 선택
pq.pop(); // 우선순위가 더 높은 프로세스 꺼내기
runningProcess->start(currentTime); // 프로세스 실행
isRunningExists = true;
TimeQuantumCount = 0;
cout << "P" << runningProcess->id;
}
cout << "-";
TimeQuantumCount++;
currentTime++; // 시간 진행
runningProcess->runningTime++;
update_waitingTime(process);
update_queue(pq);
}
// 타임 라인 출력
cout << "\n";
int historyCount = 0;
for (int i = 0; i <= currentTime; i++)
{
if (i == timeHistory[historyCount])
{
if (i != 0)
{
if(i < 10) {
cout << " ";
}
cout << " ";
}
cout << timeHistory[historyCount++];
}
else
{
cout << " ";
}
}
cout << "\n\n";
double sumWaitingTime = 0;
double sumReturnTime = 0;
for (int i = 0; i < process.size(); i++)
{
cout << "PID " << process[i]->id << " Waiting Time = " << process[i]->waitingTime << " Return Time = " << process[i]->returnTime << "\n";
sumWaitingTime += process[i]->waitingTime;
sumReturnTime += process[i]->returnTime;
}
cout << "Average Waiting Time = " << sumWaitingTime / process.size() << "\n";
cout << "Average Return Time = " << sumReturnTime / process.size() << "\n";
delete[] p;
fin.close();
return 0;
}