|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionI'm afraid to say that I am just one of those people, that unless I am doing something, I am bored. So now that I finally feel I have learnt tha basics of WPF, it is time to turn my attention to other matters. I have a long list of things that demand my attention such as (WCF/WF/CLR Via C# version 2 book), but I recently went for a new job (and got, but turned it down in the end) which required me to know a lot about threading. Whilst I consider myself to be pretty good with threading, I thought yeah I'm ok at threading, but I could always be better. So as a result of that I have decided to dedicate myself to writing a series of articles on threading in .NET. This series will undoubtely owe much to an excellent Visual Basic .NET Threading Handbook that I bought that is nicely filling the MSDN gaps for me and now you. I suspect this topic will range from simple to medium to advanced, and it will cover a lot of stuff that will be in MSDN, but I hope to give it my own spin also. So please forgive me if it does come across a bit MSDN like. I dont know the exact schedule, but it may end up being something like
I guess the best way is to just crack on. One note though before we start, I will be using C# and Visual Studio 2008. What I'm going to attempt to cover in this article will be
This article will be all about how to control the synchronization of different threads. The Need For Thread PoolingThere is a real need for thread pooling, if we remember the previous articles
we discovered there was certainly an overhead incurred by having a new thread.
This is something that the
Thread Pooling ConceptOne of the major problems affecting the responsiveness of multi-threaded applications, is the time spent spawning threads for new tasks. For example imagine a web server is a multi threaded application that can service several client requests simultaneously. For arguments saek lets assume that 10 clients are accessing the web server at the same time: If the server operates a thread per client polciy, it will create 10 new threads to service the 10 clients. There is the overhead of firstly creating the threads and then managing the threads and their associated resources through their entire lifecycle. It is also a consideration that the machine may actually run out of resources at some point. As an alternative, if the web server used a pool of threads to satisfy client requests, then it would save the time involved with spawning a new thread each time a client request is seen. This is the exact pricinple behind thread pooling. The Windows OS, maintains a pool of threads for servicing requests. if our application requests a new thread, Windows will try and fetch it from the pool. If the pool is empty, it will spawn a new thread and give it to us. Windows will dynamically manipulate the thread pool size to increase the response time for our application. Once a thread completes its assigned task, it returns to the pool and waits for the next assignment. The Size Of The Thread PoolThe .NET framework provides theThreadPool class located in the System.Threading
namespace for using thread pools in our applications. if at any time, one of the
threads in the pool is idle, then the thread pool will induce worker keep all
processors busy. If all threads in the pool are busy and work is pending, the
the ThreadPool will spawn new threads to complete the pending work.
However the number of threads created can not exceed the maximum number specified.
You can alter the size of the pool using the ThreadPool.SetMaxThreads()
and ThreadPool.SetMinThreads() methods
In case of additional thread requirement, the requests are queued until some thread finishes its assigned task and returns to the pool. Thread Pooling GlitchesThere is no doubt that the
Exploring The ThreadPoolThe main methods of the
From MSDN By far the most common methods that I think you will see used are the following methods:
Demo CodeLike I say the 2 most common methods of the
So lets consider these in turn. QueueUserWorkItem(WaitCallback)Queues a method for execution. The method executes when a thread pool thread becomes available. Is an overloaded method that allows you to create a new This first example puts a new task on the using System;
using System.Threading;
namespace QueueUserWorkItemNoState
{
/// <summary>
/// Queues a method for execution.
/// The method executes when a thread pool thread becomes available
///
/// This example was taken directly from MSDN
/// </summary>
class Program
{
static void Main(string[] args)
{
// Queue the task.
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
Console.WriteLine("Main thread does some work, then sleeps.");
// If you comment out the Sleep, the main thread exits before
// the thread pool task runs. The thread pool uses background
// threads, which do not keep the application running. (This
// is a simple example of a race condition.)
Thread.Sleep(1000);
Console.WriteLine("Main thread exits.");
Console.ReadLine();
}
// This thread procedure performs the task.
static void ThreadProc(Object stateInfo)
{
// No state object was passed to QueueUserWorkItem, so
// stateInfo is null.
Console.WriteLine("Hello from the thread pool.");
}
}
}
Which is about as simple as it gets. This results in the following:
The 2nd overload of the QueueUserWorkItem(WaitCallback, Object)Queues a method for execution, and specifies an object containing data to be used by the method. The method executes when a thread pool thread becomes available. This example uses a simple using System;
using System.Threading;
namespace QueueUserWorkItemWithState
{
// ReportData holds state information for a task that will be
// executed by a ThreadPool thread.
public class ReportData
{
public int reportID;
public ReportData(int reportID)
{
this.reportID = reportID;
}
}
/// <summary>
/// Queues a method for execution with a ReportData state object
/// </summary>
class Program
{
static void Main(string[] args)
{
// Queue the task with a state object
ReportData rd = new ReportData(15);
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), rd);
Console.WriteLine("Main thread does some work, then sleeps.");
// If you comment out the Sleep, the main thread exits before
// the thread pool task runs. The thread pool uses background
// threads, which do not keep the application running. (This
// is a simple example of a race condition.)
Thread.Sleep(1000);
Console.WriteLine("Main thread exits.");
Console.ReadLine();
}
// This thread procedure performs the task.
static void ThreadProc(Object stateInfo)
{
//get the state object
ReportData rd = (ReportData)stateInfo;
Console.WriteLine(string.Format("report {0} is running", rd.reportID));
}
}
}
Which results in the following:
So this demonstrated how to create simple tasks that can be managed by the
Well luckily the The
The attached demo project covers usage of the following overload. RegisterWaitForSingleObject(WaitHandle, WaitOrTimerCallback, Object, Int32, Boolean)For this example I will create 2 tasks within a using System;
using System.Threading;
namespace RegisterWaitForSingleObject
{
// ThreadIdentity holds state information for a task that will be
// executed by a ThreadPool thread.
public class ThreadIdentity
{
public string threadName;
public ThreadIdentity(string threadName)
{
this.threadName = threadName;
}
}
/// <summary>
/// Queues both a normal task using the ThreadPool.QueueUserWorkItem
/// and a task for execution but waits for a signal from a WaitHandle
/// before proceeding to execute
///
/// The later is done using the ThreadPool.RegisterWaitForSingleObject
/// ThreadPool method
/// </summary>
class Program
{
static AutoResetEvent ar = new AutoResetEvent(false);
static void Main(string[] args)
{
//Registers a task that will wait for a WaitHandle and will wait forever (-1 means
//never expire) and has a state object, and should execute only once
ThreadIdentity ident1 = new ThreadIdentity("RegisterWaitForSingleObject");
ThreadPool.RegisterWaitForSingleObject(ar, new WaitOrTimerCallback(ThreadProc),
ident1, -1, true);
// Queue the task as normal with a state object
ThreadIdentity ident2 = new ThreadIdentity("QueueUserWorkItem");
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), ident2);
Console.WriteLine("Main thread does some work, then sleeps.");
// If you comment out the Sleep, the main thread exits before
// the thread pool task runs. The thread pool uses background
// threads, which do not keep the application running. (This
// is a simple example of a race condition.)
Thread.Sleep(5000);
Console.WriteLine("Main thread exits." + DateTime.Now.ToLongTimeString());
Console.ReadLine();
}
// This thread procedure performs the task specified by the
// ThreadPool.QueueUserWorkItem
static void ThreadProc(Object stateInfo)
{
ThreadIdentity ident1 = (ThreadIdentity)stateInfo;
Console.WriteLine(string.Format("Hello from thread {0} at time {1}",
ident1.threadName,DateTime.Now.ToLongTimeString()));
Thread.Sleep(2000);
//set the AutoResetEvent to allow the waiting ThreadPool task
//which we added using the RegisterWaitForSingleObject to proceed
ar.Set();
}
// This thread procedure performs the task specified by the
// ThreadPool.RegisterWaitForSingleObject
static void ThreadProc(Object stateInfo, bool timedOut)
{
ThreadIdentity ident1 = (ThreadIdentity)stateInfo;
Console.WriteLine(string.Format("Hello from thread {0} at time {1}",
ident1.threadName, DateTime.Now.ToLongTimeString()));
}
}
}
Which results in the following, where is can be seen that although the 1st
work item (task) that was enqueud was the one done by using the
Using this code it should be pretty easy to see how the rest of the overloads
for the Further ReadingThere is an excellent article right here at codeproject which is "The Smart Thread Pool" project, by Ami Bar, which has thye following features * The number of threads dynamically changes according to the workload on the
threads in the pool. Its really good actually. The "The Smart Thread Pool" project by Ami Bar, can be found at this Url : Smart Thread Pool We're DoneWell that's all I wanted to say this time. I just wanted to say, I am FULLY aware that this article borrows a lot of material from various sources, I do however feel that it could alert a potential threading newbie, to classes/objects that they simply did not know to look up. For that reason I still maintain there should be something useful in this article. Well that was the idea anyway. I just hope you agree, if so tell me, and leave a vote. Next TimeNext time we will be looking at Threading in UIs. Could I just ask, if you liked this article could you please vote for it. I thank you very much Bibilography
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||