![]() |
Languages »
C# »
Applications
Beginner
License: The Code Project Open License (CPOL)
The use of Stacks in C#By punchcardRayUsing a stack to manage priorities |
C#, Windows, .NET, Visual Studio, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
Queues, stacks, deques, and linked lists are a part of the basic set of programming tools that we have at our disposal. In reviewing the examples available for stacks most dealt with simple objects such as strings and integers. Primary examples being the development of a Reverse Polish Notation Calculator. A nice article that discusses that application is available on CodeProject.
A Stack is a programmatic structure is most easily represented by a stack of dishes in your kitchen, when you go for a dish the first dish removed is normally the last one that you had put back. This is also described as Last In First Out (LIFO) structure. In .Net C# we get access to a built in stack structure through the addition of the collection class to your list of included references at the start of the program:
using System.Collections
This will give you access to the Queue, Stack, ArrayList and other classes. I have already discussed queues in
this article.
The problem that I will use to exemplify the use of a stack is a stream of jobs arriving to be processed. Each jobs will have an unique names so that we can keep track of them and a priority. The selection of a job to be processed is based on its priority. We are using a simple rule that a high priority job will be selected in front of a low priority job. A job selected for processing will be processed until it is complete.
Because the jobs may be arriving at any time we store them in a Queue as they await processing. We have a few options as to how we will process these jobs.
A..count : the number of items in the stack.push(obj) : put an object on the stack.pop() get the top item on the stack .peek(obj) : look at the next item in the stackA job class is created and a job has two properties; a JobName and a JobPriority.
class Job
{
public string jobName;
public string jobPriority;
public Job () {}
public Job (string name, string priority)
{
jobName = name;
jobPriority = priority;
}
}
We also create a JobManager class that will manage the jobs assigning
them to the processor in accordance with the business rules that we establish.
We are going to use the rules in A, this will limit the low priority jobs to only one in the stack at a time but it seems a little more fair than the rules in B because if there is a break in the job stream or a sequence of low priority jobs it will get processed in a reasonable fashion, However if there are a lot of high priority jobs it will be stuck on the stack for a while.
class JobManager
{
public Queue jobQueue = new Queue();
public Stack jobStack = new Stack();
...
}
Now for a further discussion of the processing rules. We look at the stack first as we process the jobs, and we apply the following rules
Stack Empty:A special note is needed here, when you remove an item from the stack you need to be aware that it is an object and needs to be cast back to its specific type so that it can be used e.g. : localJob = (Job)jobStack.Pop();
This is taking the object on the stack casting it to a Job and the assigning it to the variable local job.
Do this processing unstill the queue is empty.
// create several jobs
Job job1 = new Job("job1", "low");
Job job2 = new Job("job2", "low");
Job job3 = new Job("job3", "hign");
Job job4 = new Job("job4", "high");
Job job5 = new Job("job5", "low");
Job job6 = new Job("job6", "low");
// create a JobManager and then add the jobs to the queue that the
// manager manages
JobManager jobManager = new JobManager();
jobManager.jobQueue.Enqueue(job1);
jobManager.jobQueue.Enqueue(job2);
jobManager.jobQueue.Enqueue(job3);
jobManager.jobQueue.Enqueue(job4);
jobManager.jobQueue.Enqueue(job5);
jobManager.jobQueue.Enqueue(job6);
// now have the jobManager process the jobs in the queue
jobManager.ProcessJobQueue( jobManager.jobQueue);
Now the processing for the ProcessJobQueue method:
We have localJob which is the job that has just removed from the queue and nextJob which is the job that has just been exposed and is
examined with the .peek method.
The while loop will let us look at all of the items in the queue.
public void ProcessJobQueue(Queue workingQueue)
{
// get the first job in the queue
Job localJob = new Job();
Job nextJob = new Job(); // next in line we will examine with a peek
while (workingQueue.Count != 0 )
{
First the tests for the stack. Before we do the peek for the next job we test to see that the queue is not empty.
// Any source code blocks look like this
if (jobStack.Count != 0)
{
if (workingQueue.Count > 0) // look to the next item that may
// be picked
{ nextJob = (Job)workingQueue.Peek(); }
if (nextJob.jobPriority == "high")
{ // the job in the queue has a higher priority than the
// one in the stack
localJob = (Job)workingQueue.Dequeue();
Console.WriteLine("Processing High Priority Job {0} from
the Queue, the stack left alone : ", localJob.jobName);
}
if (nextJob.jobPriority == "low")
{ // the job in the queue has a same priority as
// the one in the stack
localJob = (Job)jobStack.Pop();
Console.WriteLine("Processing Job {0} POP-ed from
stack:", localJob.jobName);
}
}
if (jobStack.Count == 0)
{
localJob = (Job)workingQueue.Dequeue();
// only peek if the queue is > 0
if (workingQueue.Count > 0)
{
nextJob = (Job)workingQueue.Peek();
}
if (localJob.jobPriority == "high")
{
Console.WriteLine("Processing High priority Job
{0} directly from queue: ", localJob.jobName);
}
if ((localJob.jobPriority == "low") &&
(nextJob.jobPriority == "low"))
{
Console.WriteLine("Processing Low priority Job {0}
directly from queue with a low priority job behind
it :", localJob.jobName);
}
if ((localJob.jobPriority == "low") &&
(nextJob.jobPriority == "high"))
{
jobStack.Push(localJob);
Console.WriteLine("Stack Length: {0} ",
jobStack.Count.ToString());
Console.WriteLine("Job PUSH-ed on stack {0}",
localJob.jobName);
// get next job
localJob = (Job)workingQueue.Dequeue();
Console.WriteLine("Processing Job {0} , the previous
job was pushed onto the stack ", localJob.jobName);
}
}
When the queue is finally empty we check the stack for any jobs that it may have in it.
// at the end see if we have a job left in the stack
if (jobStack.Count != 0)
{
localJob = (Job)jobStack.Pop();
Console.WriteLine("Processing Job : {0}", localJob.jobName);
}
Processing Low priority Job job1 directly from queue with a low priority job behind it:
Stack Length: 1
Job PUSH-ed on stack job2
Processing Job job3 , the previous job was pushed onto the stack
Processing High Priority Job job4 from the Queue, the stack left alone:
Processing Job job2 POP-ed from stack:
Processing Low priority Job job5 directly from queue with a low priority job behind it:
Processing Low priority Job job6 directly from queue with a low priority job behind it:
There are two basic processor scheduling algorithms that are used by large systems: �A non-preemptive system, where jobs are executed one at a time to completion. The processor will only start the service of a low priority job if no jobs of a higher priority are scheduled. But once that processor has selected a job , it is committed to serve that job to completion even if jobs of higher priority arrive during its service. ...
In a preemptive system, several jobs can be in various stages of execution. At any moment the processor is serving a single job; but upon arrival of a job with a higher priority , the job in service is interrupted and returned to the queue. Service of the higher priority job is then started. The interrupted job will be resumed later when no jobs of a higher priority are present. Preemptive scheduling gives fast response to urgent jobs at the price of increased complexity and overhead. � [ Operating System Principals by Per Brinch Hansen Prentice-Hall 1973 pg 195]
This scheduling method we have used for this example is a variation of the non-preemptive schedule the exception being that we put the lower priority jobs on the stack as opposed to returning it back to the queue.
No changes to date.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 5 Jan 2007 Editor: Paul Conrad |
Copyright 2007 by punchcardRay Everything else Copyright © CodeProject, 1999-2009 Web18 | Advertise on the Code Project |