diff --git a/DIRECTORY.md b/DIRECTORY.md index a669f481..45f93d80 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -318,6 +318,9 @@ * [Simpsons 1 3Rd Rule](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/simpsons_1_3rd_rule.c) * [Variance](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/variance.c) +## Process Scheduling Algorithms + * [Non Preemptive Priority Scheduling](https://github.com/TheAlgorithms/C/blob/master/process_scheduling_algorithms/non_preemptive_priority_scheduling.c) + ## Project Euler * Problem 1 * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_1/sol1.c) diff --git a/process_scheduling_algorithms/non_preemptive_priority_scheduling.c b/process_scheduling_algorithms/non_preemptive_priority_scheduling.c new file mode 100644 index 00000000..2dd8ee8f --- /dev/null +++ b/process_scheduling_algorithms/non_preemptive_priority_scheduling.c @@ -0,0 +1,369 @@ +/** + * @file + * @brief + * [Non-Preemptive Priority + * Scheduling](https://en.wikipedia.org/wiki/Scheduling_(computing)) + * is a scheduling algorithm that selects the tasks to execute based on + * priority. + * + * @details + * In this algorithm, processes are executed according to their + * priority. The process with the highest priority is to be executed first and + * so on. In this algorithm, a variable is maintained known as the time quantum. + * The length of the time quantum is decided by the user. The process which is + * being executed is interrupted after the expiration of the time quantum and + * the next process with the highest priority is executed. This cycle of + * interrupting the process after every time quantum and resuming the next + * process with the highest priority continues until all the processes have + * been executed. + * @author [Aryan Raj](https://github.com/aryaraj132) + */ +#include /// for assert +#include /// for boolean data type +#include /// for IO operations (`printf`) +#include /// for memory allocation eg: `malloc`, `realloc`, `free`, `exit` +/** + * @brief Structure to represent a process + */ + typedef struct node { + int ID; ///< ID of the process node + int AT; ///< Arrival Time of the process node + int BT; ///< Burst Time of the process node + int priority; ///< Priority of the process node + int CT; ///< Completion Time of the process node + int WT; ///< Waiting Time of the process node + int TAT; ///< Turn Around Time of the process node + struct node *next; ///< pointer to the node + } node; + +/** + * @brief To insert a new process in the queue + * @param root pointer to the head of the queue + * @param id process ID + * @param at arrival time + * @param bt burst time + * @param prior priority of the process + * @returns void + */ +void insert(node **root, int id, int at, int bt, int prior) +{ + // create a new node and initialize it + node *new = (node *)malloc(sizeof(node)); + node *ptr = *root; + new->ID = id; + new->AT = at; + new->BT = bt; + new->priority = prior; + new->next = NULL; + new->CT = 0; + new->WT = 0; + new->TAT = 0; + // if the root is null, make the new node the root + if (*root == NULL) + { + *root = new; + return; + } + // else traverse to the end of the queue and insert the new node there + while (ptr->next != NULL) + { + ptr = ptr->next; + } + ptr->next = new; + return; +} +/* + * @brief To delete a process from the queue + * @param root pointer to the head of the queue + * @param id process ID + * @returns void + */ +void delete(node **root, int id) +{ + node *ptr = *root, *prev; + // if the root is null, return + if (ptr == NULL) + { + return; + } + // if the root is the process to be deleted, make the next node the root + if (ptr->ID == id) + { + *root = ptr->next; + free(ptr); + return; + } + // else traverse the queue and delete the process + while (ptr != NULL && ptr->ID != id) + { + prev = ptr; + ptr = ptr->next; + } + if (ptr == NULL) + { + return; + } + prev->next = ptr->next; + free(ptr); +} +/** + * @brief To show the process queue + * @param head pointer to the head of the queue + * @returns void + */ +void show_list(node *head) +{ + printf("Process Priority AT BT CT TAT WT \n"); + while (head != NULL) + { + printf("P%d. %d %d %d %d %d %d \n", head->ID, head->priority, head->AT, + head->BT, head->CT, head->TAT, head->WT); + head = head->next; + } +} +/** + * @brief To length process queue + * @param root pointer to the head of the queue + * @returns int total length of the queue + */ +int l_length(node **root) +{ + int count = 0; + node *ptr = *root; + while (ptr != NULL) + { + count++; + ptr = ptr->next; + } + return count; +} +/** + * @brief To update the completion time, turn around time and waiting time of + * the processes + * @param root pointer to the head of the queue + * @param id process ID + * @param ct current time + * @param wt waiting time + * @param tat turn around time + * @returns void + */ +void update(node **root, int id, int ct, int wt, int tat) +{ + node *ptr = *root; + // If process to be updated is head node + if (ptr != NULL && ptr->ID == id) + { + if (ct != 0) + { + ptr->CT = ct; + } + if (wt != 0) + { + ptr->WT = wt; + } + if (tat != 0) + { + ptr->TAT = tat; + } + return; + } + // else traverse the queue and update the values + while (ptr != NULL && ptr->ID != id) + { + ptr = ptr->next; + } + if (ct != 0) + { + ptr->CT = ct; + } + if (wt != 0) + { + ptr->WT = wt; + } + if (tat != 0) + { + ptr->TAT = tat; + } + return; +} +/** + * @brief To compare the priority of two processes based on their arrival time + * and priority + * @param a pointer to the first process + * @param b pointer to the second process + * @returns true if the priority of the first process is greater than the + * the second process + * @returns false if the priority of the first process is NOT greater than the + * second process + */ +bool compare(node *a, node *b) +{ + if (a->AT == b->AT) + { + return a->priority < b->priority; + } + else + { + return a->AT < b->AT; + } +} +/** + * @brief To calculate the average completion time of all the processes + * @param root pointer to the head of the queue + * @returns float average completion time + */ +float calculate_ct(node **root) +{ + // calculate the total completion time of all the processes + node *ptr = *root, *prior, *rpt; + int ct = 0, i, time = 0; + int n = l_length(root); + float avg, sum = 0; + node *duproot = NULL; + // create a duplicate queue + while (ptr != NULL) + { + insert(&duproot, ptr->ID, ptr->AT, ptr->BT, ptr->priority); + ptr = ptr->next; + } + ptr = duproot; + rpt = ptr->next; + // sort the queue based on the arrival time and priority + while (rpt != NULL) + { + if (!compare(ptr, rpt)) + { + ptr = rpt; + } + rpt = rpt->next; + } + // ptr is the process to be executed first. + ct = ptr->AT + ptr->BT; + time = ct; + sum += ct; + // update the completion time, turn around time and waiting time of the + // process + update(root, ptr->ID, ct, 0, 0); + delete (&duproot, ptr->ID); + // repeat the process until all the processes are executed + for (i = 0; i < n - 1; i++) + { + ptr = duproot; + while (ptr != NULL && ptr->AT > time) + { + ptr = ptr->next; + } + rpt = ptr->next; + while (rpt != NULL) + { + if (rpt->AT <= time) + { + if (rpt->priority < ptr->priority) + { + ptr = rpt; + } + } + rpt = rpt->next; + } + ct += ptr->BT; + time += ptr->BT; + sum += ct; + update(root, ptr->ID, ct, 0, 0); + delete (&duproot, ptr->ID); + } + avg = sum / n; + return avg; +} +/** + * @brief To calculate the average turn around time of all the processes + * @param root pointer to the head of the queue + * @returns float average turn around time + */ +float calculate_tat(node **root) +{ + float avg, sum = 0; + int n = l_length(root); + node *ptr = *root; + // calculate the completion time if not already calculated + if (ptr->CT == 0) + { + calculate_ct(root); + } + // calculate the total turn around time of all the processes + while (ptr != NULL) + { + ptr->TAT = ptr->CT - ptr->AT; + sum += ptr->TAT; + ptr = ptr->next; + } + avg = sum / n; + return avg; +} +/** + * @brief To calculate the average waiting time of all the processes + * @param root pointer to the head of the queue + * @returns float average waiting time + */ +float calculate_wt(node **root) +{ + float avg, sum = 0; + int n = l_length(root); + node *ptr = *root; + // calculate the completion if not already calculated + if (ptr->CT == 0) + { + calculate_ct(root); + } + // calculate the total waiting time of all the processes + while (ptr != NULL) + { + ptr->WT = (ptr->TAT - ptr->BT); + sum += ptr->WT; + ptr = ptr->next; + } + avg = sum / n; + return avg; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + // Entered processes + // printf("ID Priority Arrival Time Burst Time \n"); + // printf("1 0 5 1 \n"); + // printf("2 1 4 2 \n"); + // printf("3 2 3 3 \n"); + // printf("4 3 2 4 \n"); + // printf("5 4 1 5 \n"); + + node *root = NULL; + insert(&root, 1, 0, 5, 1); + insert(&root, 2, 1, 4, 2); + insert(&root, 3, 2, 3, 3); + insert(&root, 4, 3, 2, 4); + insert(&root, 5, 4, 1, 5); + float avgCT = calculate_ct(&root); + float avgTAT = calculate_tat(&root); + float avgWT = calculate_wt(&root); + assert(avgCT == 11); + assert(avgTAT == 9); + assert(avgWT == 6); + printf("[+] All tests have successfully passed!\n"); + // printf("Average Completion Time is : %f \n", calculate_ct(&root)); + // printf("Average Turn Around Time is : %f \n", calculate_tat(&root)); + // printf("Average Waiting Time is : %f \n", calculate_wt(&root)); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + + return 0; +}