I have asked a similar question before here, but after much thought, and implementations from those that answered me, I found that my approach might have been incorrect.
When I implement the solution given to me on this previous question the following test result appeared:
- When I ‘simulate’ multiple tasks running concurrently on multiple threads from the threadpool (by making the threads sleep at random times from 1 to 20 seconds for instance), then the model seems to work fine. I set the system to poll every 1 second to see if it can spawn another thread and all seems fine. Longer running (sleeping) threads would complete later on and threads would start and die all over the place. If I happen to run out of threads (I set it to spawn no more than 10) it would sit and wait for one to become available.
- When I however make the system do actual processing in each thread (which would take anything from 3 seconds upwards), which would involve reading data, generating XMLs saving data, sending emails and the like, the system would spawn 1, 2 or 3 threads, do processing and then just close the threads (3…2…1…) and then say 0 threads running (I added console.writelines everywhere to document the process). It would then hang around 0 threads, never picking any more work!
So I decided to state my issue again the hopes that someone has a solution. I have tried various solutions so far:
- ThreadPool: There’s always the mention that you shouldn’t over-work the ThreadPool and jobs has to be ‘quick’, but what is the definition of ‘quick’? How do I know how big/busy the ThreadPool is?
- Threads: It’s always stated that Threads are expensive and you have to handle them starting up and ending, but how do I limit them, I have tried Semaphores, ‘lock’ objects, public variables, but it no no avail
So here is what I would like to accomplish:
- I have the same job that needs to run at regular intervals, i.e. like gmail would check it’s server for new email for you every 5 seconds.
- If there is work to be done (i.e. you have new emails to be sent to your inbox), then spawn an async thread and make it start the work. This work will typically take longer than the interval stated in (1), hence the async thread, if an interval passes and the system checks again to see if there’s new work and see you have more work, it will spawn another thread and make it start the work.
- As in my example, all the jobs are the same kind of job (check of new mail), and are totally independent of eachother, they do not influence each other. If one of them fails, the rest can continue on working with no issue.
- I need there to be a limit of how many concurrent threads and maximum threads I can have. If I pick ’10’, then the system should start checking for jobs as in (1), and keep on spawning threads as in (1), until it reaches 10 threads. All new attempts on an interval to spawn a new thread should just fail (do nothing) until a thread is released again. Here I suppose the choice will be: (a) when it’s released there will already be some work queued waiting to be given to the new open thread or (b) on the next interval check if there’s new work and assign it to the new open thread.
- If there is no work, then typically the system should sit and wait, having no threads and in essence the only thing that should be running is some sort of timer
I currently use the sample in the previous question to do the following:
- I start a timer, that ticks every 1 sec
- On every tick I ‘ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork)’
- In DoWork I I instantiate a class and call various methods that does some work
…but this leads to what I mentioned before, only 3 threads that die off and then nothing.
I as thinking of doing the following:
- Set the ThreadPool to 10 thread’s
- Start a timer and in each tick ThreadPool.QueueUserWorkItem’, and just keep on doing this, hoping that the ThreadPool will handle everything else. Isn’t this what the ThreadPool is supposed to do?
Any help will be fantastic! (Sorry for the involved explanation!)
Try to have a look at the Semaphore class. You can use that to set a limit to how many threads can concurrently access a particular resource (and when I say resource, it can be anything).
Ok, edited for details:
In your class managing the threads, you create:
Then, each thread you start will call:
That will either take one slot from the semaphore and give it to the new thread, or block the new thread until a slot becomes available.
Whenever your new thread finishes its work, he (I like personalizing) MUST call, for obvious reasons:
Now, regarding the constructor, the second parameter is fairly simple: states how many concurrent threads can access the resource at any given time.
The first one is a bit trickier. The difference between the second parameter and the first one will state how many semaphore slots are reserved for the calling thread. That is, all your newly spawned threads will have access to the number of slots stated by the first parameter, and the rest of them up to the second parameter’s value will be reserved for the original thread that created the semaphore (calling thread).
In your case, for 10 max threads, you would use:
Since I posted a story anyway, let me gibe more details.
The way I will do it in the new threads, will be like this: