I think this question would actually benefit from both a C review (just change the cout
's to printf
, etc) and a C++ review since you seem to be using a very C-orientated programming style.
This post will be a C++ review.
Please note that the Turbo C++ compiler is not available to me, so my suggestions will revolve around the C++98/03 standard.
My first bit of advice would be to switch to an object-oriented approach.
Turn process
into a class and create a second class, process_queue
.
In process
, replace char name [32]
with std::string name
. This way, you don't have to worry about buffer overflows.
Refactor inc()
, pop()
, and addnode()
into member functions for the new class process_queue
.
Make pop()
return a process
instead of an int
. This is because you have a queue of process
s, not a queue of int
s.
Rename inc()
to something more readable like increment_all_wait_times()
. That's a long name, but your code will be self-documenting.
Take out the user-input logic from inc()
, pop()
, and addnode()
.
This will improve their flexibility.
A function should only do one thing, and do it well.
For function parameters, prefer the use of references over the use of pointers.
This will save you from having to check for NULL
.
Here is an idea of what a process
class might look like:
class process
{
public:
process (const std::string &name, const int burst_time = 0, const int wait_time = 0) ;
// getters
std::string name () const ;
int burst_time () const ;
int wait_time () const ;
const process* next () const ;
process* next () ;
void decrement_burst_time (const int time) ;
private:
int burst_time_;
int wait_time_;
std::string name_;
process *next_;
friend std::ostream& operator<< (std::ostream &os, const process &proc) ;
friend class process_queue ;
};
This would encapsulate your variables and (for the most part) make them read-only.
Because the process_queue
class is tightly coupled with this class, I would make it a friend class. There are two versions of the next()
method for the sake of const-correctness.
Here is an idea of what a process_queue
class might look like:
class process_queue
{
public:
process_queue () ;
~process_queue () ;
bool empty () const ;
void add_node (const process &proc) ;
void increment_all_wait_times (const int wait) ;
process pop () ;
size_t size () const ;
friend std::ostream & operator<< (std::ostream &os, const process_queue &pq) ;
private:
size_t size_ ;
process *head_;
process *tail_; // for O(1) insertions
};
This, once again, encapsulates your variables while still providing useful functionality.
Here's what a constructor implementation might look like:
process::process (const std::string &name, const int burst_time, const int wait_time)
: name_ (name), burst_time_ (burst_time), wait_time_ (wait_time), next_ (NULL)
{
}
What you see here is a constructor initialization list. It is important to initialize your variables or else you may suffer from subtle bugs.
Here is a destructor for the process_queue
class:
process_queue::~process_queue ()
{
while (size_ > 0) {
this->pop () ;
}
}
This makes sure all of our resources (memory in this case) are cleaned up when an instance of this class goes out of scope. This strategy is called RAII. RAII is important for writing exception-safe code.
Here is an example implementation of all of the above combined (somewhat sloppily):
#include <iostream>
#include <string>
#include <stdexcept>
class process_queue ;
class process
{
public:
process (const std::string &name, const int burst_time = 0, const int wait_time = 0) ;
std::string name () const ;
int burst_time () const ;
int wait_time () const ;
const process* next () const ;
process* next () ;
void decrement_burst_time (const int time) ;
private:
int burst_time_;
int wait_time_;
std::string name_;
process *next_;
friend std::ostream& operator<< (std::ostream &os, const process &proc) ;
friend class process_queue ;
};
process::process (const std::string &name, const int burst_time, const int wait_time)
: name_ (name), burst_time_ (burst_time), wait_time_ (wait_time), next_ (NULL)
{
}
std::string process::name () const
{
return name_ ;
}
int process::burst_time () const
{
return burst_time_ ;
}
int process::wait_time () const
{
return wait_time_ ;
}
const process* process::next () const
{
return next_ ;
}
process* process::next ()
{
return next_ ;
}
void process::decrement_burst_time (const int time)
{
burst_time_ -= time ;
}
std::ostream & operator<< (std::ostream &os, const process &proc)
{
os << "{Name = " << proc.name ()
<< ", Wait time = " << proc.wait_time ()
<< ", Burst time = " << proc.burst_time ()
<< ", Next = " ;
if (proc.next () != NULL) {
os << proc.next ()->name () ;
}
else {
os << "None" ;
}
os << "}" ;
return os ;
}
class process_queue
{
public:
process_queue () ;
~process_queue () ;
bool empty () const ;
void add_node (const process &proc) ;
void increment_all_wait_times (const int wait) ;
process pop () ;
size_t size () const ;
friend std::ostream & operator<< (std::ostream &os, const process_queue &pq) ;
private:
size_t size_ ;
process *head_;
process *tail_; // for O(1) insertions
};
process_queue::process_queue () : head_ (NULL), tail_ (NULL), size_ (0)
{
}
void process_queue::add_node (const process &proc)
{
process *temp = new process (proc) ;
if (tail_ != NULL) {
tail_->next_ = temp ;
if (head_ == tail_) {
head_->next_ = temp ;
}
tail_ = tail_->next_ ;
}
else {
tail_ = temp ;
head_ = tail_ ;
}
++size_ ;
}
void process_queue::increment_all_wait_times (const int wait)
{
process *temp = head_ ;
while (temp != NULL) {
temp->wait_time_ += wait ;
temp = temp->next_ ;
}
}
// Pops the head off.
process process_queue::pop ()
{
if (head_ == NULL) {
throw std::range_error ("process_queue::pop() called while the process_queue was empty.") ;
}
process ret = *head_ ;
process *temp = head_ ;
head_ = head_->next_ ;
delete temp ;
--size_ ;
return ret ;
}
bool process_queue::empty () const
{
return (size_ == 0) ;
}
size_t process_queue::size () const
{
return size_ ;
}
std::ostream & operator<< (std::ostream &os, const process_queue &pq)
{
process *temp = pq.head_ ;
while (temp != NULL) {
os << *temp << "\n" ;
temp = temp->next () ;
}
return os ;
}
process_queue::~process_queue ()
{
while (size_ > 0) {
this->pop () ;
}
}
namespace scheduler
{
void run_first_come_first_serve (process_queue &pq)
{
std::cout << "Running first-come-first-serve scheduler with no preemption." "\n" ;
while (pq.empty () == false) {
process proc = pq.pop () ;
std::cout << "Running " << proc.name () << "\n" ;
std::cout << proc.name () << " finished running after " << (proc.burst_time () + proc.wait_time ()) << " ns." "\n" ;
pq.increment_all_wait_times (proc.burst_time ()) ;
std::cout << "Queue:\n" << pq << "\n" ;
}
}
}
int main(void)
{
process notepad ("notepad.exe", 500) ;
process firefox ("firefox.exe", 1500) ;
process excel ("excel.exe", 100) ;
process visual_studio ("visual studio.exe", 200) ;
process super_virus ("super virus.exe", 1000) ;
process_queue pq ;
pq.add_node (notepad) ;
pq.add_node (firefox) ;
pq.add_node (excel) ;
pq.add_node (visual_studio) ;
pq.add_node (super_virus) ;
scheduler::run_first_come_first_serve (pq) ;
return 0 ;
}
cin
andcout
). \$\endgroup\$<iostream.h>
? Callingcout
andcin
with nostd::
orusing namespace std;
? Is this working code? \$\endgroup\$simulated_time += 100;
whenever there's something that involves delay in your model. I'd suggest using variable names that are more descriptive than e, p, q, t, or tt. Lose theinc
function by storing the entry/arrival time in the queue rather than the wait: wait = time at pop - entry time. \$\endgroup\$int main(void)
is not a legal declaration formain
. Useint main()
\$\endgroup\$