From 95ed72a45275da29096e3bc1da83ae72fa98c4a9 Mon Sep 17 00:00:00 2001 From: Pratyush219 <53852042+Pratyush219@users.noreply.github.com> Date: Fri, 15 Oct 2021 22:04:00 +0530 Subject: [PATCH] feat: Added implementation of FCFS CPU scheduling algorithm (#1684) * FCFS scheduling algorithm in operating system Added C++ implementation of FCFS scheduling algorithm in a new directory Operating-System/Scheduing-Algorithms * Renamed files and directories to match guidelines * Updated comments * Added comments for member variables of FCFS class * Deleted .vscode directory * Replaced array of tuples with vector of tuples Replaced formatted printf with cout and iomanip flags Removed unused code blocks * Replaced array of tuples with vector of tuples * Removed nested directory * updating DIRECTORY.md * clang-format and clang-tidy fixes for c95495b4 * clang-format and clang-tidy fixes for 732f247d * Updated the documentation and used unsigned int for non-negative integers * clang-format and clang-tidy fixes for 295f0cc6 * clang-format and clang-tidy fixes for 31f05910 * Added test cases using random number generator * Replaced time(0) with time(nullptr) * clang-format and clang-tidy fixes for 40d663d3 * Fixed documentation * Rearranged code * clang-format and clang-tidy fixes for b40a2801 * clang-format and clang-tidy fixes for 243dcc15 * Updated documentation * clang-format and clang-tidy fixes for 899ff7ea * Fixed some typos * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review * Replaced int with uint32_t in lines 259 and 263 Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 3 + cpu_scheduling_algorithms/fcfs_scheduling.cpp | 290 ++++++++++++++++++ 2 files changed, 293 insertions(+) create mode 100644 cpu_scheduling_algorithms/fcfs_scheduling.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 207692b7e..84a3b276f 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -29,6 +29,9 @@ * [Vigenere Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/vigenere_cipher.cpp) * [Xor Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/xor_cipher.cpp) +## Cpu Scheduling Algorithms + * [Fcfs Scheduling](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/cpu_scheduling_algorithms/fcfs_scheduling.cpp) + ## Data Structures * [Avltree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/avltree.cpp) * [Binary Search Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/binary_search_tree.cpp) diff --git a/cpu_scheduling_algorithms/fcfs_scheduling.cpp b/cpu_scheduling_algorithms/fcfs_scheduling.cpp new file mode 100644 index 000000000..4fc61af6b --- /dev/null +++ b/cpu_scheduling_algorithms/fcfs_scheduling.cpp @@ -0,0 +1,290 @@ +/** + * @file + * @brief Implementation of FCFS CPU scheduling algorithm + * @details + * FCFS is a non-preemptive CPU scheduling algorithm in which whichever process + * arrives first, gets executed first. If two or more processes arrive + * simultaneously, the process with smaller process ID gets executed first. + * @link https://bit.ly/3ABNXOC + * @author [Pratyush Vatsa](https://github.com/Pratyush219) + */ + +#include /// for sorting +#include /// for assert +#include /// random number generation +#include /// for time +#include /// for formatting the output +#include /// for IO operations +#include /// for std::priority_queue +#include /// for std::unordered_set +#include /// for std::vector + +using std::cin; +using std::cout; +using std::endl; +using std::get; +using std::left; +using std::make_tuple; +using std::priority_queue; +using std::rand; +using std::srand; +using std::tuple; +using std::unordered_set; +using std::vector; +/** + * @brief Comparator function for sorting a vector + * @tparam S Data type of Process ID + * @tparam T Data type of Arrival time + * @tparam E Data type of Burst time + * @param t1 First tuple + * @param t2 Second tuple + * @returns true if t1 and t2 are in the CORRECT order + * @returns false if t1 and t2 are in the INCORRECT order + */ +template +bool sortcol(tuple& t1, tuple& t2) { + if (get<1>(t1) < get<1>(t2)) { + return true; + } else if (get<1>(t1) == get<1>(t2) && get<0>(t1) < get<0>(t2)) { + return true; + } + return false; +} + +/** + * @class Compare + * @brief Comparator class for priority queue + * @tparam S Data type of Process ID + * @tparam T Data type of Arrival time + * @tparam E Data type of Burst time + */ +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. + * @link Refer to + * https://www.geeksforgeeks.org/comparator-class-in-c-with-examples/ for + * detailed description of comparator + * @returns true if the tuples SHOULD be swapped + * @returns false if the tuples SHOULDN'T be swapped + */ + bool operator()(tuple& t1, + tuple& t2) { + // Compare arrival times + if (get<1>(t2) < get<1>(t1)) { + return true; + } + // If arrival times are same, then compare Process IDs + else if (get<1>(t2) == get<1>(t1)) { + return get<0>(t2) < get<0>(t1); + } + return false; + } +}; + +/** + * @class FCFS + * @brief Class which implements the FCFS scheduling algorithm + * @tparam S Data type of Process ID + * @tparam T Data type of Arrival time + * @tparam E Data type of Burst time + */ +template +class FCFS { + /** + * Priority queue of schedules(stored as tuples) of processes. + * In each tuple + * 1st element: Process ID + * 2nd element: Arrival Time + * 3rd element: Burst time + * 4th element: Completion time + * 5th element: Turnaround time + * 6th element: Waiting time + */ + priority_queue, + vector>, + 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 adding + // 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 + * @param burst Burst time of the process + * @returns void + * + */ + void addProcess(S id, T arrival, E burst) { + // 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); + schedule.push(t); + idList.insert(id); + } + } + + /** + * @brief Algorithm for scheduling CPU processes according to the First Come + * First Serve(FCFS) scheduling algorithm. + * + * @details FCFS is a non-preemptive algorithm in which the process which + * arrives first gets executed first. If two or more processes arrive + * together then the process with smaller process ID runs first (each + * process has a unique proces ID). + * + * I used a min priority queue of tuples to accomplish this task. The + * processes are ordered by their arrival times. If arrival times of some + * processes are equal, then they are ordered by their process ID. + * + * @returns void + */ + vector> scheduleForFcfs() { + // 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 + // 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); + + // Completion time of the current process will be same as time + // elapsed so far + get<3>(cur) = timeElapsed; + + // Turnaround time = Completion time - Arrival time + get<4>(cur) = get<3>(cur) - get<1>(cur); + + // Waiting time = Turnaround time - Burst time + get<5>(cur) = get<4>(cur) - get<2>(cur); + + result.push_back(cur); + schedule.pop(); + } + return result; + } + + /** + * @brief Utility function for printing the status of each process after + * execution + * @returns void + */ + void printResult() { + cout << "Status of all the proceses post completion is as follows:" + << endl; + + 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) + << left << "Turnaround Time" << std::setw(17) << left + << "Waiting Time" << endl; + + for (size_t i{}; i < result.size(); i++) { + cout << std::setprecision(2) << std::fixed << std::setw(17) << left + << get<0>(result[i]) << std::setw(17) << left + << get<1>(result[i]) << std::setw(17) << left + << get<2>(result[i]) << std::setw(17) << left + << get<3>(result[i]) << std::setw(17) << left + << get<4>(result[i]) << std::setw(17) << left + << get<5>(result[i]) << endl; + } + } +}; + +/** + * @brief Function to be used for testing purposes. This function guarantees the + * correct solution for FCFS scheduling algorithm. + * @param input the input data + * @details Sorts the input vector according to arrival time. Processes whose + * arrival times are same get sorted according to process ID For each process, + * completion time, turnaround time and completion time are calculated, inserted + * in a tuple, which is added to the vector result. + * @returns A vector of tuples consisting of process ID, arrival time, burst + * time, completion time, turnaround time and waiting time for each process. + */ +template +vector> get_final_status( + vector> input) { + sort(input.begin(), input.end(), sortcol); + vector> result(input.size()); + double timeElapsed = 0; + for (size_t i{}; i < input.size(); i++) { + T arrival = get<1>(input[i]); + E burst = get<2>(input[i]); + + if (arrival > timeElapsed) { + timeElapsed += arrival - timeElapsed; + } + timeElapsed += burst; + double completion = timeElapsed; + double turnaround = completion - arrival; + double waiting = turnaround - burst; + + get<0>(result[i]) = get<0>(input[i]); + get<1>(result[i]) = arrival; + get<2>(result[i]) = burst; + get<3>(result[i]) = completion; + get<4>(result[i]) = turnaround; + get<5>(result[i]) = waiting; + } + return result; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + for (int i{}; i < 1000; i++) { + srand(time(nullptr)); + uint32_t n = 1 + rand() % 1000; + FCFS readyQueue; + vector> input(n); + + for (uint32_t i{}; i < n; i++) { + get<0>(input[i]) = i; + srand(time(nullptr)); + get<1>(input[i]) = 1 + rand() % 10000; + srand(time(nullptr)); + get<2>(input[i]) = 1 + rand() % 10000; + } + + for (uint32_t i{}; i < n; i++) { + readyQueue.addProcess(get<0>(input[i]), get<1>(input[i]), + get<2>(input[i])); + } + vector> + res = get_final_status(input); + assert(res == readyQueue.scheduleForFcfs()); + // readyQueue.printResult(); + } + cout << "All the tests have successfully passed!" << endl; +} + +/** + * @brief Entry point of the program + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +}