|
|||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThe use of multiple threads in an application is a proven method of keeping your application responsive to a user while making use of the CPU in between user events. The
DeliverablesI've included the threading class library (BlackHen.Threading.dll) along with a sample program, a unit testing library (BlackHen.Threading.Tests.dll), and class level documentation. The documentation is a compiled help file and was produced with NDoc. The unit testing library is to be used with the NUnit tool. The sample program allows you to specify the number of threads to use and the concurrency limit (how much work can be done concurrently) in the bottom left pane. You can use the bottom right pane to start producing work. The top pane shows the number of work items in each state (the processing pipe line), it refreshes every 1/5th of a second. A progress bar appears at the bottom to show you the percentage of work completed. The sample work is a random sleep between 100 and 500 milliseconds. While work is being performed, you can still modify the settings and produce more work; since, this was the aim of the project! DesignThe major entities of this design are:
Many implementations of multithreading combine the Interfaces are defined that provide the contract between the work queue and the other entities. The public interface IWork
{
void Perform();
}
public interface IWorkItem : IWork
{
IWorkQueue WorkQueue {get; set;}
WorkItemState State {get; set;}
Exception FailedException {get; set;}
ThreadPriority Priority {get; set;}
}
The public interface IResourcePool
{
void BeginWork(IWorkItem workItem);
}
The public interface IWorkQueue
{
void WorkItemStateChanged (IWorkItem workItem, WorkItemState previousState);
void HandleResourceException(ResourceExceptionEventArgs e);
}
Work ItemThe
As each state is entered, the time is captured for auditing purposes and its When a work item is added to the work queue, it enters either the Scheduled or Queued state depending upon the work load. Eventually, a resource (work thread) will get the work item and the work item enters the Running state. If an exception is thrown while performing the work item, the Failing state is entered. A Work QueueThe The public void Add(IWorkItem workItem) {
// Assign it to this queue.
workItem.WorkQueue = this;
// Can we schedule it for execution now?
if (!pausing && runningItems < ConcurrentLimit)
{
workItem.State = WorkItemState.Scheduled;
}
else
{
// Add the workitem to queue.
lock (this)
{
queue.Push(workItem);
workItem.State = WorkItemState.Queued;
}
}
}
The
WorkThreadPoolThe Work is scheduled for execution by calling the public void BeginWork(IWorkItem workItem)
{
if (workItem == null)
throw new ArgumentNullException();
lock (this)
{
// Queue the work.
workQueue.Push(workItem);
// If all workers are busy, then create a thread if the limit
// is not reached.
if (waiters == 0 && workers.Count < MaxThreads)
CreateThread();
// Wakeup a worker.
Monitor.Pulse(this);
}
}
The
Exception HandlingExceptions are a standard way of signaling an error; the method that detects an error The class library specifies how exceptions are handled based on where (in the processing pipeline) it was thrown. It also defines the events an application can attach to detect the exception.
The following code illustrates how a worker thread implements the above scenarios: public void Start()
{
try
{
while (true)
{
IWorkItem work = null;
lock (threadPool)
{
if (threadPool.workQueue.Count == 0)
{
Monitor.Wait(threadPool);
}
work = (IWorkItem) threadPool.workQueue.Pop();
}
DoWork(work);
}
}
catch(Exception e)
{
// This should not happen!!!
threadPool.OnThreadException
(new ResourceExceptionEventArgs(this, e));
}
}
public void DoWork (IWorkItem workItem)
{
try
{
workItem.State = WorkItemState.Running;
try
{
workItem.Perform();
}
catch (Exception e)
{
workItem.FailedException = e;
workItem.State = WorkItemState.Failing;
}
workItem.State = WorkItemState.Completed;
}
catch (Exception e)
{
// If no work queue for the item, then let the WorkThreadPool raise
// the exception event.
if (workItem == null || workItem.WorkQueue == null)
throw;
workItem.WorkQueue.HandleResourceException
(new ResourceExceptionEventArgs(this, e));
}
}
Future WorkThe following enhancements are planned:
References
|
||||||||||||||||||||||||||||||||