mirror of
https://github.com/TheAlgorithms/C-Plus-Plus.git
synced 2026-05-08 06:43:14 +08:00
Update non_preemptive_sjf_scheduling.cpp
This commit is contained in:
@@ -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 <algorithm> /// for sorting
|
||||
#include <cassert> /// for assert
|
||||
#include <random> /// random number generation
|
||||
#include <iomanip> /// for formatting the output
|
||||
#include <iostream> /// for IO operations
|
||||
#include <queue> /// for std::priority_queue
|
||||
#include <unordered_set> /// for std::unordered_set
|
||||
#include <vector> /// for std::vector
|
||||
#include <algorithm> /// for sorting
|
||||
#include <cassert> /// for assert
|
||||
#include <iomanip> /// for formatting the output
|
||||
#include <iostream> /// for IO operations
|
||||
#include <queue> /// for std::priority_queue
|
||||
#include <random> /// random number generation
|
||||
#include <unordered_set> /// for std::unordered_set
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
@@ -59,13 +60,14 @@ bool sortcol(tuple<S, T, E>& t1, tuple<S, T, E>& t2) {
|
||||
template <typename S, typename T, typename E>
|
||||
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.
|
||||
* <a href="https://www.geeksforgeeks.org/comparator-class-in-c-with-examples/"> detailed description of comparator </a>
|
||||
* <a
|
||||
* href="https://www.geeksforgeeks.org/comparator-class-in-c-with-examples/">
|
||||
* detailed description of comparator </a>
|
||||
* @returns true if the tuples SHOULD be swapped
|
||||
* @returns false if the tuples SHOULDN'T be swapped
|
||||
*/
|
||||
@@ -92,7 +94,7 @@ class Compare {
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
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<tuple<S, T, E, double, double, double>,
|
||||
vector<tuple<S, T, E, double, double, double>>,
|
||||
Compare<S, T, E>> schedule;
|
||||
|
||||
Compare<S, T, E>>
|
||||
schedule;
|
||||
|
||||
// Stores final status of all the processes after completing the execution.
|
||||
vector<tuple<S, T, E, double, double, double>> result;
|
||||
|
||||
|
||||
// Stores process IDs. Used for confirming absence of a process while it.
|
||||
unordered_set<S> 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<S, T, E, double, double, double> 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<tuple<S, T, E, double, double, double>> 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<S, T, E, double, double, double> 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<tuple<S, T, E, double, double, double>>& processes) {
|
||||
|
||||
void printResult(
|
||||
const vector<tuple<S, T, E, double, double, double>>& 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 <typename S, typename T, typename E>
|
||||
vector<tuple<S, T, E, double, double, double>> get_final_status(
|
||||
vector<tuple<S, T, E>> input) {
|
||||
|
||||
// Sort the processes based on Arrival time and then Burst time
|
||||
sort(input.begin(), input.end(), sortcol<S, T, E>);
|
||||
/**
|
||||
* @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 <typename S, typename T, typename E>
|
||||
vector<tuple<S, T, E, double, double, double>> get_final_status(
|
||||
vector<tuple<S, T, E>> input) {
|
||||
// Sort the processes based on Arrival time and then Burst time
|
||||
sort(input.begin(), input.end(), sortcol<S, T, E>);
|
||||
|
||||
// Result vector to hold the final status of each process
|
||||
vector<tuple<S, T, E, double, double, double>> result(input.size());
|
||||
double timeElapsed = 0;
|
||||
// Result vector to hold the final status of each process
|
||||
vector<tuple<S, T, E, double, double, double>> 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<tuple<uint32_t, uint32_t, uint32_t, double, double, double>> finalResult;
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t, double, double, double>>
|
||||
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<uint32_t, uint32_t, uint32_t> readyQueue;
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t, double, double, double>> input(n);
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t, double, double, double>>
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user