diff --git a/cpu_scheduling_algorithms/non_preemptive_sjf_scheduling.cpp b/cpu_scheduling_algorithms/non_preemptive_sjf_scheduling.cpp index bbc05c056..0b0de343d 100644 --- a/cpu_scheduling_algorithms/non_preemptive_sjf_scheduling.cpp +++ b/cpu_scheduling_algorithms/non_preemptive_sjf_scheduling.cpp @@ -2,21 +2,22 @@ * @file * @brief Implementation of SJF CPU scheduling algorithm * @details - * shortest job first (SJF), also known as shortest job next (SJN), is a scheduling policy - * that selects for execution the waiting process with the smallest execution time. - * SJN is a non-preemptive algorithm. Shortest remaining time is a preemptive variant of SJN. + * shortest job first (SJF), also known as shortest job next (SJN), is a + * scheduling policy that selects for execution the waiting process with the + * smallest execution time. SJN is a non-preemptive algorithm. Shortest + * remaining time is a preemptive variant of SJN. * @link https://www.guru99.com/shortest-job-first-sjf-scheduling.html * @author [Lakshmi Srikumar](https://github.com/LakshmiSrikumar) */ -#include /// for sorting -#include /// for assert -#include /// random number generation -#include /// for formatting the output -#include /// for IO operations -#include /// for std::priority_queue -#include /// for std::unordered_set -#include /// for std::vector +#include /// for sorting +#include /// for assert +#include /// for formatting the output +#include /// for IO operations +#include /// for std::priority_queue +#include /// random number generation +#include /// for std::unordered_set +#include /// for std::vector using std::cin; using std::cout; @@ -59,13 +60,14 @@ bool sortcol(tuple& t1, tuple& t2) { template class Compare { public: - - /** + /** * @param t1 First tuple * @param t2 Second tuple * @brief A comparator function that checks whether to swap the two tuples * or not. - * detailed description of comparator + * + * detailed description of comparator * @returns true if the tuples SHOULD be swapped * @returns false if the tuples SHOULDN'T be swapped */ @@ -92,7 +94,7 @@ class Compare { */ template class SJF { -/** + /** * Priority queue of schedules(stored as tuples) of processes. * In each tuple * 1st element: Process ID @@ -104,16 +106,17 @@ class SJF { */ priority_queue, vector>, - Compare> schedule; - + Compare> + schedule; + // Stores final status of all the processes after completing the execution. vector> result; - + // Stores process IDs. Used for confirming absence of a process while it. unordered_set idList; public: - /** + /** * @brief Adds the process to the ready queue if it isn't already there * @param id Process ID * @param arrival Arrival time of the process @@ -122,7 +125,7 @@ class SJF { * */ void addProcess(S id, T arrival, E burst) { - // Add if a process with process ID as id is not found in idList. + // Add if a process with process ID as id is not found in idList. if (idList.find(id) == idList.end()) { tuple t = make_tuple(id, arrival, burst, 0, 0, 0); @@ -131,35 +134,39 @@ class SJF { } } - /** - * @brief Algorithm for scheduling CPU processes according to the Shortest Job - First (SJF) scheduling algorithm. - * - * @details Non pre-emptive SJF is an algorithm that schedules processes based on the length - * of their burst times. The process with the smallest burst time is executed first. - * In a non-preemptive scheduling algorithm, once a process starts executing, - * it runs to completion without being interrupted. - * - * I used a min priority queue because it allows you to efficiently pick the process - * with the smallest burst time in constant time, by maintaining a priority order where - * the shortest burst process is always at the front. - * - * @returns void - */ + /** + * @brief Algorithm for scheduling CPU processes according to the Shortest Job + First (SJF) scheduling algorithm. + * + * @details Non pre-emptive SJF is an algorithm that schedules processes based + on the length + * of their burst times. The process with the smallest burst time is executed + first. + * In a non-preemptive scheduling algorithm, once a process starts executing, + * it runs to completion without being interrupted. + * + * I used a min priority queue because it allows you to efficiently pick the + process + * with the smallest burst time in constant time, by maintaining a priority + order where + * the shortest burst process is always at the front. + * + * @returns void + */ vector> scheduleForSJF() { - // Variable to keep track of time elapsed so far + // Variable to keep track of time elapsed so far double timeElapsed = 0; while (!schedule.empty()) { tuple cur = schedule.top(); - - // If the current process arrived at time t2, the last process + + // If the current process arrived at time t2, the last process // completed its execution at time t1, and t2 > t1. if (get<1>(cur) > timeElapsed) { timeElapsed += get<1>(cur) - timeElapsed; } - + // Add Burst time to time elapsed timeElapsed += get<2>(cur); @@ -184,8 +191,8 @@ class SJF { * @returns void */ - void printResult(const vector>& processes) { - + void printResult( + const vector>& processes) { cout << std::setw(17) << left << "Process ID" << std::setw(17) << left << "Arrival Time" << std::setw(17) << left << "Burst Time" << std::setw(17) << left << "Completion Time" << std::setw(17) @@ -194,60 +201,61 @@ class SJF { for (const auto& process : processes) { cout << std::setprecision(2) << std::fixed << std::setw(17) << left - << get<0>(process) << std::setw(17) << left - << get<1>(process) << std::setw(17) << left - << get<2>(process) << std::setw(17) << left - << get<3>(process) << std::setw(17) << left - << get<4>(process) << std::setw(17) << left - << get<5>(process) << endl; + << get<0>(process) << std::setw(17) << left << get<1>(process) + << std::setw(17) << left << get<2>(process) << std::setw(17) + << left << get<3>(process) << std::setw(17) << left + << get<4>(process) << std::setw(17) << left << get<5>(process) + << endl; } } }; - /** - * @brief Computes the final status of processes after applying non-preemptive SJF scheduling - * @tparam S Data type of Process ID - * @tparam T Data type of Arrival time - * @tparam E Data type of Burst time - * @param input A vector of tuples containing Process ID, Arrival time, and Burst time - * @returns A vector of tuples containing Process ID, Arrival time, Burst time, - * Completion time, Turnaround time, and Waiting time - */ - template - vector> get_final_status( - vector> input) { - - // Sort the processes based on Arrival time and then Burst time - sort(input.begin(), input.end(), sortcol); +/** + * @brief Computes the final status of processes after applying non-preemptive + * SJF scheduling + * @tparam S Data type of Process ID + * @tparam T Data type of Arrival time + * @tparam E Data type of Burst time + * @param input A vector of tuples containing Process ID, Arrival time, and + * Burst time + * @returns A vector of tuples containing Process ID, Arrival time, Burst time, + * Completion time, Turnaround time, and Waiting time + */ +template +vector> get_final_status( + vector> input) { + // Sort the processes based on Arrival time and then Burst time + sort(input.begin(), input.end(), sortcol); - // Result vector to hold the final status of each process - vector> result(input.size()); - double timeElapsed = 0; + // Result vector to hold the final status of each process + vector> result(input.size()); + double timeElapsed = 0; - for (size_t i = 0; i < input.size(); i++) { + for (size_t i = 0; i < input.size(); i++) { // Extract Arrival time and Burst time - T arrival = get<1>(input[i]); - E burst = get<2>(input[i]); + T arrival = get<1>(input[i]); + E burst = get<2>(input[i]); - // If the CPU is idle, move time to the arrival of the next process - if (arrival > timeElapsed) { - timeElapsed = arrival; - } + // If the CPU is idle, move time to the arrival of the next process + if (arrival > timeElapsed) { + timeElapsed = arrival; + } - // Update timeElapsed by adding the burst time - timeElapsed += burst; + // Update timeElapsed by adding the burst time + timeElapsed += burst; - // Calculate Completion time, Turnaround time, and Waiting time - double completion = timeElapsed; - double turnaround = completion - arrival; - double waiting = turnaround - burst; + // Calculate Completion time, Turnaround time, and Waiting time + double completion = timeElapsed; + double turnaround = completion - arrival; + double waiting = turnaround - burst; - // Store the results in the result vector - result[i] = make_tuple(get<0>(input[i]), arrival, burst, completion, turnaround, waiting); - } - - return result; - } + // Store the results in the result vector + result[i] = make_tuple(get<0>(input[i]), arrival, burst, completion, + turnaround, waiting); + } + + return result; +} /** * @brief Self-test implementations @@ -255,16 +263,18 @@ class SJF { */ static void test() { // A vector to store the results of all processes across all test cases. - vector> finalResult; + vector> + finalResult; - for (int i{}; i < 10; i++) { - std::random_device rd; // Seeding + for (int i{}; i < 10; i++) { + std::random_device rd; // Seeding std::mt19937 eng(rd()); - std::uniform_int_distribution<> distr(1, 10); + std::uniform_int_distribution<> distr(1, 10); - uint32_t n = distr(eng); + uint32_t n = distr(eng); SJF readyQueue; - vector> input(n); + vector> + input(n); // Generate random arrival and burst times for (uint32_t i{}; i < n; i++) { @@ -279,10 +289,11 @@ static void test() { // Add processes to the queue for (uint32_t i{}; i < n; i++) { - readyQueue.addProcess(get<0>(input[i]), get<1>(input[i]), get<2>(input[i])); + readyQueue.addProcess(get<0>(input[i]), get<1>(input[i]), + get<2>(input[i])); } - // Perform SJF scheduling + // Perform SJF schedulings auto finalResult = readyQueue.scheduleForSJF(); // Print processes after scheduling @@ -290,10 +301,7 @@ static void test() { readyQueue.printResult(finalResult); } cout << "All the tests have successfully passed!" << endl; - } - - - +} /** * @brief Entry point of the program