Skip to content

Commit 48743d3

Browse files
LakshmiSrikumarrealstealthninjagithub-actions[bot]
authored
feat: add non-preemptive SJF scheduling (#2801)
* Create non_preemptive_sjf_scheduling.cpp * Update non_preemptive_sjf_scheduling.cpp Co-authored-by: realstealthninja <[email protected]> * Update non_preemptive_sjf_scheduling.cpp Co-authored-by: realstealthninja <[email protected]> * Update non_preemptive_sjf_scheduling.cpp Co-authored-by: realstealthninja <[email protected]> * added a vector to store and print the final result * Update non_preemptive_sjf_scheduling.cpp Co-authored-by: realstealthninja <[email protected]> * Update non_preemptive_sjf_scheduling.cpp Co-authored-by: realstealthninja <[email protected]> * Create non_preemptive_sjf_scheduling.cpp I have done the necessary changes. The test function will generate 10 different testcases in which it will print the before and after the SJF scheduling. @realstealthninja Kindly review the PR and please accept it. * Delete non_preemptive_sjf_scheduling.cpp * Update cpu_scheduling_algorithms/non_preemptive_sjf_scheduling.cpp Co-authored-by: realstealthninja <[email protected]> * Update non_preemptive_sjf_scheduling.cpp * Update non_preemptive_sjf_scheduling.cpp * Update cpu_scheduling_algorithms/non_preemptive_sjf_scheduling.cpp Co-authored-by: realstealthninja <[email protected]> * Update non_preemptive_sjf_scheduling.cpp * Update non_preemptive_sjf_scheduling.cpp * clang-format and clang-tidy fixes for 57e670c * chore: remove spaces * Update dynamic_programming/unbounded_0_1_knapsack.cpp --------- Co-authored-by: realstealthninja <[email protected]> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 34e7231 commit 48743d3

File tree

1 file changed

+316
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)