Skip to content

Commit 80127bb

Browse files
Create non_preemptive_sjf_scheduling.cpp
1 parent faff217 commit 80127bb

File tree

1 file changed

+296
-0
lines changed

1 file changed

+296
-0
lines changed

non_preemptive_sjf_scheduling.cpp

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
/**
2+
* @file
3+
* @brief Implementation of SJF CPU scheduling algorithm
4+
* @details
5+
* shortest job first (SJF), also known as shortest job next (SJN), is a scheduling policy
6+
* that selects for execution the waiting process with the smallest execution time.
7+
* SJN is a non-preemptive algorithm. Shortest remaining time is a preemptive variant of SJN.
8+
* @link https://www.guru99.com/shortest-job-first-sjf-scheduling.html
9+
* @author [Lakshmi Srikumar](https://github.com/LakshmiSrikumar)
10+
*/
11+
12+
#include <algorithm> /// for sorting
13+
#include <cassert> /// for assert
14+
#include <cstdlib> /// random number generation
15+
#include <ctime> /// for time
16+
#include <iomanip> /// for formatting the output
17+
#include <iostream> /// for IO operations
18+
#include <queue> /// for std::priority_queue
19+
#include <unordered_set> /// for std::unordered_set
20+
#include <vector> /// for std::vector
21+
22+
using std::cin;
23+
using std::cout;
24+
using std::endl;
25+
using std::get;
26+
using std::left;
27+
using std::make_tuple;
28+
using std::priority_queue;
29+
using std::rand;
30+
using std::srand;
31+
using std::tuple;
32+
using std::unordered_set;
33+
using std::vector;
34+
35+
/**
36+
* @brief Comparator function for sorting a vector
37+
* @tparam S Data type of Process ID
38+
* @tparam T Data type of Arrival time
39+
* @tparam E Data type of Burst time
40+
* @param t1 First tuple
41+
* @param t2 Second tuple
42+
* @returns true if t1 and t2 are in the CORRECT order
43+
* @returns false if t1 and t2 are in the INCORRECT order
44+
*/
45+
template <typename S, typename T, typename E>
46+
bool sortcol(tuple<S, T, E>& t1, tuple<S, T, E>& t2) {
47+
if (get<1>(t1) < get<1>(t2)) {
48+
return true;
49+
} else if (get<1>(t1) == get<1>(t2) && get<0>(t1) < get<0>(t2)) {
50+
return true;
51+
}
52+
return false;
53+
}
54+
55+
/**
56+
* @class Compare
57+
* @brief Comparator class for priority queue
58+
* @tparam S Data type of Process ID
59+
* @tparam T Data type of Arrival time
60+
* @tparam E Data type of Burst time
61+
*/
62+
63+
template <typename S, typename T, typename E>
64+
class Compare {
65+
public:
66+
67+
/**
68+
* @param t1 First tuple
69+
* @param t2 Second tuple
70+
* @brief A comparator function that checks whether to swap the two tuples
71+
* or not.
72+
* @link Refer to
73+
* https://www.geeksforgeeks.org/comparator-class-in-c-with-examples/ for
74+
* detailed description of comparator
75+
* @returns true if the tuples SHOULD be swapped
76+
* @returns false if the tuples SHOULDN'T be swapped
77+
*/
78+
79+
bool operator()(tuple<S, T, E, double, double, double>& t1,
80+
tuple<S, T, E, double, double, double>& t2) {
81+
// Compare burst times for SJF
82+
if (get<2>(t2) < get<2>(t1)) {
83+
return true;
84+
}
85+
// If burst times are the same, compare arrival times
86+
else if (get<2>(t2) == get<2>(t1)) {
87+
return get<1>(t2) < get<1>(t1);
88+
}
89+
return false;
90+
}
91+
};
92+
93+
/**
94+
* @class SJF
95+
* @brief Class which implements the SJF scheduling algorithm
96+
* @tparam S Data type of Process ID
97+
* @tparam T Data type of Arrival time
98+
* @tparam E Data type of Burst time
99+
*/
100+
template <typename S, typename T, typename E>
101+
class SJF {
102+
/**
103+
* Priority queue of schedules(stored as tuples) of processes.
104+
* In each tuple
105+
* 1st element: Process ID
106+
* 2nd element: Arrival Time
107+
* 3rd element: Burst time
108+
* 4th element: Completion time
109+
* 5th element: Turnaround time
110+
* 6th element: Waiting time
111+
*/
112+
priority_queue<tuple<S, T, E, double, double, double>,
113+
vector<tuple<S, T, E, double, double, double>>,
114+
Compare<S, T, E>> schedule;
115+
116+
// Stores final status of all the processes after completing the execution.
117+
vector<tuple<S, T, E, double, double, double>> result;
118+
119+
// Stores process IDs. Used for confirming absence of a process while it.
120+
unordered_set<S> idList;
121+
122+
public:
123+
/**
124+
* @brief Adds the process to the ready queue if it isn't already there
125+
* @param id Process ID
126+
* @param arrival Arrival time of the process
127+
* @param burst Burst time of the process
128+
* @returns void
129+
*
130+
*/
131+
void addProcess(S id, T arrival, E burst) {
132+
// Add if a process with process ID as id is not found in idList.
133+
if (idList.find(id) == idList.end()) {
134+
tuple<S, T, E, double, double, double> t =
135+
make_tuple(id, arrival, burst, 0, 0, 0);
136+
schedule.push(t);
137+
idList.insert(id);
138+
}
139+
}
140+
141+
/**
142+
* @brief Algorithm for scheduling CPU processes according to the Shortest Job
143+
First (SJF) scheduling algorithm.
144+
*
145+
* @details Non pre-emptive SJF is an algorithm that schedules processes based on the length
146+
* of their burst times. The process with the smallest burst time is executed first.
147+
* In a non-preemptive scheduling algorithm, once a process starts executing,
148+
* it runs to completion without being interrupted.
149+
*
150+
* I used a min priority queue because it allows you to efficiently pick the process
151+
* with the smallest burst time in constant time, by maintaining a priority order where
152+
* the shortest burst process is always at the front.
153+
*
154+
* @returns void
155+
*/
156+
157+
vector<tuple<S, T, E, double, double, double>> scheduleForSJF() {
158+
// Variable to keep track of time elapsed so far
159+
double timeElapsed = 0;
160+
161+
while (!schedule.empty()) {
162+
tuple<S, T, E, double, double, double> cur = schedule.top();
163+
164+
// If the current process arrived at time t2, the last process
165+
// completed its execution at time t1, and t2 > t1.
166+
if (get<1>(cur) > timeElapsed) {
167+
timeElapsed += get<1>(cur) - timeElapsed;
168+
}
169+
170+
// Add Burst time to time elapsed
171+
timeElapsed += get<2>(cur);
172+
173+
// Completion time of the current process will be same as time
174+
// elapsed so far
175+
get<3>(cur) = timeElapsed;
176+
177+
// Turnaround time = Completion time - Arrival time
178+
get<4>(cur) = get<3>(cur) - get<1>(cur);
179+
180+
// Waiting time = Turnaround time - Burst time
181+
get<5>(cur) = get<4>(cur) - get<2>(cur);
182+
183+
result.push_back(cur);
184+
schedule.pop();
185+
}
186+
return result;
187+
}
188+
/**
189+
* @brief Utility function for printing the status of each process after
190+
* execution
191+
* @returns void
192+
*/
193+
194+
void printResult() {
195+
cout << "Status of all processes post completion is as follows:" << endl;
196+
197+
cout << std::setw(17) << left << "Process ID" << std::setw(17) << left
198+
<< "Arrival Time" << std::setw(17) << left << "Burst Time"
199+
<< std::setw(17) << left << "Completion Time" << std::setw(17)
200+
<< left << "Turnaround Time" << std::setw(17) << left
201+
<< "Waiting Time" << endl;
202+
203+
for (size_t i{}; i < result.size(); i++) {
204+
cout << std::setprecision(2) << std::fixed << std::setw(17) << left
205+
<< get<0>(result[i]) << std::setw(17) << left
206+
<< get<1>(result[i]) << std::setw(17) << left
207+
<< get<2>(result[i]) << std::setw(17) << left
208+
<< get<3>(result[i]) << std::setw(17) << left
209+
<< get<4>(result[i]) << std::setw(17) << left
210+
<< get<5>(result[i]) << endl;
211+
}
212+
}
213+
};
214+
215+
/**
216+
* @brief Computes the final status of processes after applying non-preemptive SJF scheduling
217+
* @tparam S Data type of Process ID
218+
* @tparam T Data type of Arrival time
219+
* @tparam E Data type of Burst time
220+
* @param input A vector of tuples containing Process ID, Arrival time, and Burst time
221+
* @returns A vector of tuples containing Process ID, Arrival time, Burst time,
222+
* Completion time, Turnaround time, and Waiting time
223+
*/
224+
225+
template <typename S, typename T, typename E>
226+
vector<tuple<S, T, E, double, double, double>> get_final_status(
227+
vector<tuple<S, T, E>> input) {
228+
229+
// Sort the processes based on Arrival time and then Burst time
230+
sort(input.begin(), input.end(), sortcol<S, T, E>);
231+
232+
// Result vector to hold the final status of each process
233+
vector<tuple<S, T, E, double, double, double>> result(input.size());
234+
double timeElapsed = 0;
235+
236+
for (size_t i = 0; i < input.size(); i++) {
237+
// Extract Arrival time and Burst time
238+
T arrival = get<1>(input[i]);
239+
E burst = get<2>(input[i]);
240+
241+
// If the CPU is idle, move time to the arrival of the next process
242+
if (arrival > timeElapsed) {
243+
timeElapsed = arrival;
244+
}
245+
246+
// Update timeElapsed by adding the burst time
247+
timeElapsed += burst;
248+
249+
// Calculate Completion time, Turnaround time, and Waiting time
250+
double completion = timeElapsed;
251+
double turnaround = completion - arrival;
252+
double waiting = turnaround - burst;
253+
254+
// Store the results in the result vector
255+
result[i] = make_tuple(get<0>(input[i]), arrival, burst, completion, turnaround, waiting);
256+
}
257+
258+
return result;
259+
}
260+
261+
/**
262+
* @brief Self-test implementations
263+
* @returns void
264+
*/
265+
static void test() {
266+
for (int i{}; i < 1000; i++) {
267+
srand(time(nullptr));
268+
uint32_t n = 1 + rand() % 1000;
269+
SJF<uint32_t, uint32_t, uint32_t> readyQueue;
270+
vector<tuple<uint32_t, uint32_t, uint32_t>> input(n);
271+
272+
for (uint32_t i{}; i < n; i++) {
273+
get<0>(input[i]) = i;
274+
srand(time(nullptr));
275+
get<1>(input[i]) = 1 + rand() % 10000;
276+
srand(time(nullptr));
277+
get<2>(input[i]) = 1 + rand() % 10000;
278+
}
279+
280+
for (uint32_t i{}; i < n; i++) {
281+
readyQueue.addProcess(get<0>(input[i]), get<1>(input[i]),
282+
get<2>(input[i]));
283+
}
284+
readyQueue.scheduleForSJF();
285+
//readyQueue.printResult();
286+
}
287+
cout << "All the tests have successfully passed!" << endl;
288+
}
289+
290+
/**
291+
* @brief Entry point of the program
292+
*/
293+
int main() {
294+
test();
295+
return 0;
296+
}

0 commit comments

Comments
 (0)