Ah, good old multi-threading. Always fun, and often a source of headaches. With C# and .NET, those headaches don't go away, but there are some nice wrappers that make working with threads a little bit easier. Today we are going to take a look at how to use C#'s ThreadPool - which is probably the simplest way to make a multi-threaded C# app.
A thread pool takes away all the need to manage your threads - all you have to do is essentially say "hey! someone should go do this work!", and a thread in the process' thread pool will pick up the task and go execute it. And that is all there is to it. Granted, you still have to keep threads from stepping on each other's toes, and you probably care about when these 'work items' are completed - but it is at least a really easy way to queue up a work item.
In fact, working with the ThreadPool is so easy, I'm going to throw
all the code at you at once. Below is a pretty simple test app that
gives 5 (or NumThreads) work items to the ThreadPool, waits for them
all to complete, and then prints out all the answers. I will walk
through the code step by step below:
using System;
using System.Threading;
namespace ThreadPoolTest
{
class Program
{
private const int NumThreads = 5;
private static int[] inputArray;
private static double[] resultArray;
private static ManualResetEvent[] resetEvents;
private static void Main(string[] args)
{
inputArray = new int[NumThreads];
resultArray = new double[NumThreads];
resetEvents = new ManualResetEvent[NumThreads];
Random rand = new Random();
for (int s = 0; s < NumThreads; s++)
{
inputArray[s] = rand.Next(1,5000000);
resetEvents[s] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), (object)s);
}
Console.WriteLine("Waiting...");
WaitHandle.WaitAll(resetEvents);
Console.WriteLine("And the answers are: ");
for (int i = 0; i < NumThreads; i++)
Console.WriteLine(inputArray[i] + " -> " + resultArray[i]);
}
private static void DoWork(object o)
{
int index = (int)o;
for (int i = 1; i < inputArray[index]; i++)
resultArray[index] += 1.0 / (i * (i + 1));
resetEvents[index].Set();
}
}
}
We have three arrays at the top of the program: one for input to the
work items (inputArray), one for the results (resultArray), and one
for the
ManualResetEvents
(resetEvents). The first two are self explanatory, but what is a
ManualResetEvent? Well, it is an object that allows one thread to
signal another thread when something happens. In the case of this code,
we use these events to signal the main thread that a work item has been
completed.
So we initialize these arrays, and then we get to a for loop, which is
where we will be pushing out these work items. First, we make a random
value for the initial input (cause random stuff is always more fun!),
then we create a ManualResetEvent with its signaled state initially
set to false, and then we queue the work item. Thats right, all you have
to do to push a work item out for the ThreadPool to do is call
ThreadPool.QueueUserWorkItem.
So what are we queuing here? Well, we are saying that a thread in the
thread pool should run the method DoWork, with the argument s. Any
method that you want to queue up for the thread pool to run needs to
take one argument, an object, and return void. The argument will end up
being whatever you passed in as the second argument to the
QueueUserWorkItem call - and in this case is the 'index' of this work
item (the index in the various arrays that it needs to work with). And
it makes sense that the method would have to return void - because it
isn't actually returning 'to' anything, it is running out there all on
its own as a separate thread.
So what are we doing in this DoWork function? Not that much in this
case, just a simple summation. The important part is the very last call
of the function, which is hit when all the work for this work item is
done - resetEvents[index].Set(). This triggers the ManualResetEvent
for this work item - signaling the main thread that the work is all done
here.
Back up in main thread land, after it has pushed all these work items
onto the ThreadPool queue, we hit the very important call
WaitHandle.WaitAll(resetEvents). This causes the main thread to block
here until all the ManualResetEvent objects in the resetEvents array
signal. When all of them have signaled, that means that all the work
units have been completed, and so we continue on and print out all the
results. The results change because we are seeding with random values,
but here is one example output:
Waiting...
And the answers are:
3780591 -> 0.991001809831479
3555614 -> 0.991163782231558
2072717 -> 0.989816715560308
2264396 -> 0.989982111762391
544144 -> 0.99066981542858
Pretty simple, eh? There are a couple things to note, though. The default thread pool size for a process is 25 threads, and while you can change this number, this resource is not infinite. If all of the threads in the pool are currently occupied with other tasks, new work items will be queued up, but they won't get worked on until one of the occupied threads finishes its current task. This generally isn't a problem unless you are giving the pool very large quantities of work. And really, you should never assume that a task is executed immediately after you queue it, because there is no guarantee of that at all.
That's it for this intro to thread pools in C#. Thanks for reading.
Thanks mate! Great help!
Thanks man that was a good intro to Threading
Hi , this is a queue .. What if i have some 1000 items in an array that needs to be updated to the database 50 at a time ie a function that takes a parameter and based on that parameter it will fetch some data and update the database. Can we make sure that once a thread has finished a work it will start next work without waiting for the other threads to finish .. thanks in advance
Kumar,
The answer to this question is yes. But you have to research the JOIN keyword in System.Threading in order to have a "new thread" wait for an "old thread" to complete.
hw can i pass more than one argument to my Dowork function ?
Kind of. The WaitCallback delegate only allows you to specify a single object as the parameter, however, since an array is still an object, you could fill one with each argument you need and pass the array to the DoWork function. This has the downside of having to know what index is what object, but it's a solution.
A better solution is to simply create a small container class that has members for each object. Then simply pass the container class to the DoWork function.
array[] of objects ;)
that solves it.. great!
This code worked well in my project. One question? If I attempt to run more than 64 threads I get the following error: "The number of waithandles must be less than or equal to 64." I spent several hours researching the error and could not find a satisfactory answer.
My project takes a set of name / address records from a database and runs each one against a remote web service in an effort to update the person name, address or phone. The input records could number in the thousands and it speeds processing if I can make several hundred requests to the remote service at a time.
This is a response to William's question, "How do you wait for more than 64"
The answer is, "don't do that". What you should do is use ONE event object, and have an "int" (I'll call it numBusy) which tracks how many workers are not finished yet. Lets say you are going to run 100 work items. Before queueing up any work items, set numBusy to 100 and proceed to queue up the work items.
Summary of changes: 1) Add "int numBusy" member variable. 2) Get rid of the array "resetEvents" and create a single "doneEvent" event. 3) At the end of the DoWork function, remove "resetEvents[index].Set();" add the following code:
And to wait for all of the work items to complete, you simply do:
doneEvent.WaitOne();
How does it work? "Interlocked.Decrement" will subtract 1 from an int in a thread-safe manner, and return the new value. When the last work item has decremented the value to zero, it sets the event.
This technique is far more efficient than setting a bunch of separate events. Setting an event is a pretty expensive operation, because it has to make an expensive call all the way down into kernel mode to set the event. An interlocked decrement is one instruction, and will take nanoseconds to complete. This technique will work for over 2 billion work items (up to int.MaxValue items).
For robust code, you should wrap the work in a try-finally block, and put the interlocked decrement code in the finally. This way, it won't hang forever if one of the work items cause an exception to be thrown.
Hello Doug Gale!
The solution you presented for William’s problem is very good one. Can you suggest me any alternatives to it if we do not know the number of threads to be spawned before hand.
Waiting for your reply.
Thanks!
we need a like button 4 this...thanks...damn
Thanks a lot for this solution, Doug.
You can find a complete code example here: http://www.codeproject.com/Articles/142341/Solved-The-number-of-WaitHandles-must-be-less-than.aspx
nice article well written...however if i have 50 workitems and i should use 5 threads (max). Then what changes in the code are required.
Great article !
However my problem ist to detect the end of only one thread launched by the threadpool
And I can not use WaitAll because my second thread makes call to the main thread using events : DoWork is calling itself some method in the secundary thread
So, how can I detect that DoWork is finished in order to enable some button in a form in the main thread ?
Olivier Check if you are in the background thread. You dont want your background thread to call foreground methods
what if i want to run a loop more than number of threads? I mean what if i need to call Dowork function more than number of threads in Threadpool? how do we return status here ?
I've been using this code in production for about 4 months and it works well but I would like to warn everyone about an issue you might encounter.
QueueUserWorkItem uses the static thread pool which is limited to 25 threads per process. In my case I used the code in an a web service that makes multiple calls in parallel to a remote web service. I setup my code to make 25 calls in parallel using QueueUserWorkItem not realizing that .net uses this same thread pool for it's processes. To make matters worse, when I set up the web service in IIS I put it in the same application pool as the asp.net web site that was calling the web service. Everytime the web site called the web service, the web service would consume the available threads in the thread pool, causing the web site to freeze. The web site would unfreeze when threads became available.
The resolution was to place the web service and the web site in separate application pools. This creates a separate static pool for each process and significantly increased the performance of the system as a whole.
How do you:
?2) Get rid of the array "resetEvents" and create a single "doneEvent" event.
?
Answer to question "How do you get rid of the array "resetEvents" and create a single "doneEvent" event?"
I haven't used this code in a production enviroment but it seems to work OK.
Thank you for the code example. In the application I have, the above approach works if I run everything from the dev studio. But if I launch the app directly, my app hangs (doneEvent.WaitOne()). I have searched and not found a plausible explanation for this. I would appreciate any pointers to address this.
Very helpfull. Thanks a lot.
This example is perfect and i used it for many of my multi thread applications. I had to do some tweaks here and there to make it fit my situation. This helped me reduceing the processing time for one of my programs from a day to just matter of few hours.
Regards, Amardeep Puri
Hello,
Really nice, and the comments were quite helpful too.. but I have a question; Mainly because I am concerned about this sentence from the article: This generally isn't a problem unless you are giving the pool very large quantities of work.
I have a web service WSA (lets say this will have the main thread) and it will call another method F() within the WS. This method F() does a LOT of xml processing and database inserts and deletes, for each and every call. The website which calls this webservice is a very high volume one. There are easily more than 500 requests per minute, across multiple web servers.
The bottomline is the method F() does a lot of work.. The Calling Thread does not need any results back from F(), so I thought I would use :
. I wasn't planning on using the ManualResetEvents, and even after reading the article, I don't think I need to, since I don't need the results back. Is that correct?
My concern is, when WSA calls F(), if F() takes longer compared to the speed with which WSA itself receives the requests, what are the repercussions? I mean, will the main thread (in WSA) still be able to keep up and continue with its work irrespective of F(), or will it create problems at some point? I thought that the fact that we're calling asynchronously means that it wouldn't create problems for the main thread, but because of the high volume and the critical nature of this call, I just want to make sure.
I use a System.Collections.Generic.Queue to hold pending requests. In my case I'm processing records from a .csv file so I load each row into an object and insert the object into the queue. I then use a While loop that runs until the queue is empty. Each iteration of the loop spawns 50 threads that deenqueue the requests and make the appropriate calls to DoWork. Let me know if you need a code sample and I will throw something together.
You might also want to check out this article on MSDN:
http://msdn.microsoft.com/en-us/magazine/dd419664.aspx
It's not 100% relevant but might give you some ideas.
chrisn, I really appreciate if you could post a sample code here utilizing the Queue object as you mentioned above.
Here's a sample using a queue. I used XElements because my application makes calls to external web services but you could enqueue a text file or objects.
Hichrisn , Thank so much for nice article.I want to some advice to u in "static void DoWork(object o)" this method,
resultArray[Int32.Parse(request.Element("ThreadId").Value)] = new XElement("Response", new XElement("Result", Int32.Parse(request.Element("ThreadId").Value) \< 12 ? true : false));
on which basis u r comparing ThreadId \< 12. This 12 is ur no. of Xml requests or Maximum ThreadId of xml request. Pls reply as soon as possible. abhishek.udiya@diaspark.com
There is one piece of this sample that I just don't understand. It seems to me the reason behind using the Queue is to be sure not to add more than 25 threads to the ThreadPool. Is that correct?
If so, then isn't this code assuming that the second time it hits the while loop that it has freed up some of the threads? What happens if all 25 threads are still running and you don't want to keep adding to the ThreadPool until some threads get freed up?
I am thinking something like this. Though I don't know if there are issues with this:
Thanks mr Tallest! fantastic article. This stuff can be soooo complicated but you managed to keep your code and explanation terrifically tight and really help me understand what was going on.
Thank you also commenters, all food for thought.
Michael
Dear all, I have a multithread program, each thread is do some work and write out to "Logfile.txt". All thread is write to "Logfile.txt". Now I want to use a thread that manage write above file, it's mean thread1 write file complete and then thread2 write file...
But I can't write program as description above. can you help me ???
Excellent article - most helpful!
Hi in my case I create a thread pool of size n if n jobs are availbale for processing in database.But once it starts processing polling stops and though some file are ready for processing they have to wait until the the previous thread pool completes.So i want to add threads to the thread pool even if it processes other jobs how to do that. This is peice of code where i have used thread pooling: doneEvents[i] = new ManualResetEvent(false); PreprocessThreadManager p = new PreprocessThreadManager(i, doneEvents[i]); preprocessArray[i] = p;
Preprocessor preprocessRequest = new Preprocessor(); preprocessRequest.JobID = jobID; preprocessRequest.UUID = UUID; preprocessRequest.InFile = sourceFile; preprocessRequest.OutFile = destinationFile; ////preprocessRequest.ABitRate = Convert.ToInt32(ConfigurationManager.AppSettings["Civolution_ABitRate"].ToString()); ThreadPool.QueueUserWorkItem(p.ThreadPoolCallback, preprocessRequest); i++;
Good intro to threading..
Hi, I implemented long running process in 'DoWork' method which includes processing the html file using XmlTextReader. The error I got is 'Operation has timed out'. Can anyone help me?
Thanks, great explanation. :)
Hi,
Great article. Thank you. I am just wondering about something. Since resultArray and resetEvents are static objects; shouldn't we put a lock or something similar in the DoWork method when modifying these objects so that concurrent threads don't attempt to access them at the same time? Or is that not an issue?
Thanks again.
Good Article
Hi, I have a windows application in which i have consumed 6 services each having 20+ methods in it. I want to asynchronously call each method in each service by passing some parameters and also store their respective execution time. I have created a function 'DynamicInvoke' which on run time creates an instance of the service client and invokes the function based on the parameter passed.
Below is the code of the function 'DynamicInvoke':
[language] public void DynamicInvoke(string namespaceName, string serviceName, string methodName, params object[] paramaters) { // Create an instance of the service client Type calledType = Type.GetType(namespaceName + "." + serviceName); object tempObject = Activator.CreateInstance(calledType);
string returnTypeString = string.Format(namespaceName + "." + methodName + "Result"); Type returnType = Type.GetType(returnTypeString); //Get the method info MethodInfo tempMethodInfo = calledType.GetMethod(methodName); DateTime requestTime = DateTime.Now; object responseClass = tempMethodInfo.Invoke(tempObject, paramaters);// Asychronously Call This DateTime responseTime = DateTime.Now; TimeSpan executionTime = responseTime - requestTime; PropertyInfo tempStatusProperty = returnType.GetProperty("Status"); object statusValue = tempStatusProperty.GetValue(responseClass, null); if (statusValue.ToString() == "SUCCESS") { //On success make an entry in database } } [/language]
Great post... I like it...:)
Hi This is an amazing lession thanks Two questions: it is good only if the thread do the same function but if they need to do differnt function do I need to create new pool and I do not mean the case I have switch, but in case that after few minutes of running or a few code lines I need to run a new thread with a new function?
second in case I use common data resource I.E integer do I need to lock it every time or that the pool managment know to do is automatically?
nice post and very easy to understand thanks!
is it the only way ?
i want to send mail in batches using multithreading. Each thread will pick a batch of ids and send mail.Please help
this is great one!!!!!!!! please check out the following links for more details of threading pool in C#... http://mindstick.com/Articles/8a6ce546-6516-46c7-9398-edc0d28a38f1/?ThreadPool%20in%20C#%20Programming
why did you set resetEvents[s] = new ManualResetEvent(false);
Those are paired with the line:
The author is using these to wait for every thread to complete before displaying the "answers". False is passed in so that when WaitAll is called, execution will block until all the threads are finished.
i have the following code and the method ProcessQueueMessages needs a parameter to be passed 1.e. public void ProcessQueueMessages(CE_MessageRequest_Staging stagingRequest) { // do some thing }
in all the above examples you are just calling dowork method with no parameters.
could anyone please help me how to pass the parameter to the method that is executed by a thread from the pool.
wow this was really helpful, thanks
Sai, Try this: http://msdn.microsoft.com/en-us/library/3dasc8as(v=VS.80).aspx
Here is an example of separating the number of input item from the number of threads:
Hi,
I was reading your article and I would like to appreciate you for making it very simple and understandable. This article gives me a basic idea of C# ThreadPool and it will help me a lot. Following link...
http://www.mindstick.com/Articles/8a6ce546-6516-46c7-9398-edc0d28a38f1/?ThreadPool%20in%20C#%20Programming
also having nice post with wonderful explanation on C# ThreadPool.
Thank you very much!
Very nice, i thank you for this article, will be putting it to use :D, sure beets programing multi threads, and stopping them, this actually does all the work for you!
-MadApples
There is a certain amount of overhead associated with starting and stopping a thread. In most of the applications, many threads would be idle most of the time or perform small operations and die quickly it is desirable to conserve resources by sharing already created threads. To do this, .NET provides a ThreadPool class that is easy to use.
Gym.prathap .Net Training
Thanks
If i have 500 task ,i create 50 threads for completing task at a time,then how i resigned thread to remaining task.And in that how i use thread pool.