I wrote a program that implements the Round Robin planning algorithm. The total number of processes is read directly from the input standard, and for each process the arrival time and execution time are specified. The time interval of each process (quantum) is read from the standard input. I calculated the average response time, the average waiting time and the display is made in the order of execution of the processes.
My question is, is this implementation correct? What else could I improve or what problems does implementation have?
code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "lab.h"
int main()
{
int i, limit, total = 0, x, counter = 0, time_quantum;
int wait_time = 0, turnaround_time = 0, arrival_time[10], burst_time[10], temp[10];
float average_wait_time, average_turnaround_time;
do
{
printf("\nEnter Total Number of Processes: ");
if(scanf("%d", &limit) != 1)
{
err_msg("Failed to read integer");
exit(1);
}
} while (limit < 0);
x = limit;
for(i = 0; i < limit; i++)
{
printf("\nEnter Details of Process[%d]\n", i + 1);
do
{
printf("Arrival Time:\t");
if(scanf("%d", &arrival_time[i]) != 1)
{
err_msg("Failed to read integer");
exit(1);
}
} while ( *(arrival_time + i) < 0);
do
{
printf("Burst Time:\t");
if(scanf("%d", &burst_time[i]) != 1)
{
err_msg("Failed to read integer");
exit(1);
}
} while ( *(burst_time + i) < 0);
temp[i] = burst_time[i];
}
do
{
printf("\nEmter Time Quantum:\t");
if(scanf("%d", &time_quantum) != 1)
{
err_msg("Failed to read integer");
exit(1);
}
} while ( time_quantum < 0 );
printf("\nProcess ID\t\tBurst Time\t Turnaround Time\t Waiting Time\n");
for(total = 0, i = 0; x != 0;)
{
if(temp[i] <= time_quantum && temp[i] > 0)
{
total = total + temp[i];
temp[i] = 0;
counter = 1;
}
else if(temp[i] > 0)
{
temp[i] = temp[i] - time_quantum;
total = total + time_quantum;
}
if(temp[i] == 0 && counter == 1)
{
x--;
printf("\nProcess[%d]\t\t%d\t\t %d\t\t\t %d", i + 1, burst_time[i], total - arrival_time[i], total - arrival_time[i] - burst_time[i]);
wait_time = wait_time + total - arrival_time[i] - burst_time[i];
turnaround_time = turnaround_time + total - arrival_time[i];
counter = 0;
}
if(i == limit - 1)
{
i = 0;
}
else if(arrival_time[i + 1] <= total)
{
i++;
}
else
{
i = 0;
}
}
average_wait_time = wait_time * 1.0 / limit;
average_turnaround_time = turnaround_time * 1.0 / limit;
printf("\n\nAverage Waiting Time:\t%f", average_wait_time);
printf("\nAvg Turnaround Time:\t%f\n", average_turnaround_time);
return 0;
}
lab.h content:
/* Our own header, to be included *after* all standard system headers */
#ifndef __ourhdr_h
#define __ourhdr_h
#include <sys/types.h> /* required for some of our prototypes */
#include <stdio.h> /* for convenience */
#include <stdlib.h> /* for convenience */
#include <string.h> /* for convenience */
#include <unistd.h> /* for convenience */
#define MAXLINE 4096 /* max line length */
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/* default file access permissions for new files */
#define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
/* default permissions for new directories */
typedef void Sigfunc(int); /* for signal handlers */
/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
#if defined(SIG_IGN) && !defined(SIG_ERR)
#define SIG_ERR ((Sigfunc *)-1)
#endif
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
/* prototypes for our own functions */
char *path_alloc(int *); /* {Prog pathalloc} */
int open_max(void); /* {Prog openmax} */
void clr_fl(int, int); /* {Prog setfl} */
void set_fl(int, int); /* {Prog setfl} */
void pr_exit(int); /* {Prog prexit} */
void pr_mask(const char *); /* {Prog prmask} */
Sigfunc *signal_intr(int, Sigfunc *);/* {Prog signal_intr_function} */
int tty_cbreak(int); /* {Prog raw} */
int tty_raw(int); /* {Prog raw} */
int tty_reset(int); /* {Prog raw} */
void tty_atexit(void); /* {Prog raw} */
#ifdef ECHO /* only if <termios.h> has been included */
struct termios *tty_termios(void); /* {Prog raw} */
#endif
void sleep_us(unsigned int); /* {Ex sleepus} */
ssize_t readn(int, void *, size_t);/* {Prog readn} */
ssize_t writen(int, const void *, size_t);/* {Prog writen} */
int daemon_init(void); /* {Prog daemoninit} */
int s_pipe(int *); /* {Progs svr4_spipe bsd_spipe} */
int recv_fd(int, ssize_t (*func)(int, const void *, size_t));
/* {Progs recvfd_svr4 recvfd_43bsd} */
int send_fd(int, int); /* {Progs sendfd_svr4 sendfd_43bsd} */
int send_err(int, int, const char *);/* {Prog senderr} */
int serv_listen(const char *); /* {Progs servlisten_svr4 servlisten_44bsd} */
int serv_accept(int, uid_t *); /* {Progs servaccept_svr4 servaccept_44bsd} */
int cli_conn(const char *); /* {Progs cliconn_svr4 cliconn_44bsd} */
int buf_args(char *, int (*func)(int, char **));
/* {Prog bufargs} */
int ptym_open(char *); /* {Progs ptyopen_svr4 ptyopen_44bsd} */
int ptys_open(int, char *); /* {Progs ptyopen_svr4 ptyopen_44bsd} */
#ifdef TIOCGWINSZ
pid_t pty_fork(int *, char *, const struct termios *,
const struct winsize *); /* {Prog ptyfork} */
#endif
int lock_reg(int, int, int, off_t, int, off_t);
/* {Prog lockreg} */
#define read_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLK, F_RDLCK, offset, whence, len)
#define readw_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLKW, F_RDLCK, offset, whence, len)
#define write_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, len)
#define writew_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLKW, F_WRLCK, offset, whence, len)
#define un_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLK, F_UNLCK, offset, whence, len)
pid_t lock_test(int, int, off_t, int, off_t);
/* {Prog locktest} */
#define is_readlock(fd, offset, whence, len) \
lock_test(fd, F_RDLCK, offset, whence, len)
#define is_writelock(fd, offset, whence, len) \
lock_test(fd, F_WRLCK, offset, whence, len)
void err_dump(const char *, ...); /* {App misc_source} */
void err_msg(const char *, ...);
void err_quit(const char *, ...);
void err_ret(const char *, ...);
void err_sys(const char *, ...);
void err_init(const char *);
void log_msg(const char *, ...); /* {App misc_source} */
void log_open(const char *, int, int);
void log_quit(const char *, ...);
void log_ret(const char *, ...);
void log_sys(const char *, ...);
void TELL_WAIT(void); /* parent/child from {Sec race_conditions} */
void TELL_PARENT(pid_t);
void TELL_CHILD(pid_t);
void WAIT_PARENT(void);
void WAIT_CHILD(void);
#endif /* __ourhdr_h */
```
1 Answer 1
The variable names are very descriptive and well thought out. The code is definitely readable.
In Main Prefer return Over exit
In the C programming language return from main is the same as calling exit()
from any function. The current exit()
statements don't make sense since they should be returns, or they should be in functions.
DRY Code
There is a programming principle called the Don't Repeat Yourself Principle sometimes referred to as DRY code. If you find yourself repeating the same code mutiple times it is better to encapsulate it in a function. If it is possible to loop through the code that can reduce repetition as well.
This code is repeated at least 4 times, so it should be a function:
if(scanf("%d", &limit) != 1)
{
err_msg("Failed to read integer");
exit(1);
}
Complexity
The function main()
is too complex (does too much). As programs grow in size the use of main()
should be limited to calling functions that parse the command line, calling functions that set up for processing, calling functions that execute the desired function of the program, and calling functions to clean up after the main portion of the program.
There is also a programming principle called the Single Responsibility Principle that applies here. The Single Responsibility Principle states:
that every module, class, or function should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by that module, class or function.
It is also important to keep in mind that it is easier to solve difficult problems by breaking them up into smaller and smaller problems until the are easy to solve. In programming this means writting functions.
There are 3 tasks presented in the code
- Get the number of processes
- Get the process details
- process the details
Each of the tasks corresponds to a function.
Declare the Variables as Needed
In the original version of C back in the 1970s and 1980s variables had to be declared at the top of the function. That is no longer the case, and a recommended programming practice to declare the variable as needed. In C the language doesn't provide a default initialization of the variable so variables should be initialized as part of the declaration. For readability and maintainability each variable should be declared and initialized on its own line.
int i = 0;
int limit = 0;
int total = 0;
int x = 0;
int counter = 0;
int time_quantum = 0;
int wait_time = 0;
int turnaround_time = 0;
int arrival_time[10];
int burst_time[10];
int temp[10];
float average_wait_time = 0.0;
float average_turnaround_time = 0.0;
If you break the program up into functions the scope of the variables above is reduced since they will only be used in the functions where they are needed.
Magic Numbers
There are Magic Numbers in the main()
function (10), it might be better to create symbolic constants for them to make the code more readble and easier to maintain. These numbers may be used in many places and being able to change them by editing only one line makes maintainence easier.
Numeric constants in code are sometimes referred to as Magic Numbers, because there is no obvious meaning for them. There is a discussion of this on stackoverflow.
There are also system provided symbolic constants that can be used if you include stdlib.h that would make the code a little clearer, these are EXIT_SUCCESS and EXIT_FAILURE. The exit()
statements would then be exit(EXIT_FAILURE)
.
#define MAX_PROCESSES 10
int arrival_time[MAX_PROCESSES];
int burst_time[MAX_PROCESSES ];
int temp[MAX_PROCESSES];
Use a Struct to Group Related Variables
The three arrays all seem to be related to processes, it is possible in the C programming language to group related variables so that separate arrays aren't necessary:
struct myProcess
{
int arrival_time;
int burst_time;
int temp;
};
struct myProcess MyProcessess[MAX_PROCESSES];
```
Explore related questions
See similar questions with these tags.
"lab.h"
header. \$\endgroup\$