0
\$\begingroup\$

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 */
```
\$\endgroup\$
2
  • 5
    \$\begingroup\$ "is this implementation correct?" isn't entirely on topic -- the site is for code you've already validated to be working to the best of your ability. What steps have you taken to validate that it matches your specification? It's OK if you overlooked something, but if you haven't tried to validate it at all, then you might want to write some tests first and share them before asking for a code review. Keep in mind you can edit your question until an answer is posted, to address this and the missing "lab.h" header. \$\endgroup\$
    – ggorlen
    Jan 25, 2022 at 15:02
  • 2
    \$\begingroup\$ You don't seem to know if it works. One of the requirements for posting here (see help center) is that code has to be working to the best of your knowledge before posting. \$\endgroup\$
    – Mast
    Jan 28, 2022 at 9:59

1 Answer 1

1
\$\begingroup\$

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

  1. Get the number of processes
  2. Get the process details
  3. 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];

```
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.