Re: Delegate BeginInvoke and ManualResetEvent.WaitOne()
- From: "Peter Duniho" <NpOeStPeAdM@xxxxxxxxxxxxxxxx>
- Date: Mon, 11 Feb 2008 10:25:29 -0800
On Mon, 11 Feb 2008 09:56:01 -0800, Alphapage <Alphapage@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote:
Here is an example:
ManualResetEvent waiter;
delegate DoWorkDelegate;
void DoWork()
{
waiter.WaitOne();
}
Don't do that.
void SubMethodnvoke()
{
DoWorkDelegate.BeginInvoke(DoWork);
}
I do something like this when I open Submethods in my app.
I want to know how many submethods I can open.
I think this asynchronous delegate works as a ThreadPool, so if I open more
than the pool threads limit (ie 25 threads by default) I will probably have
some troubles.
Yes. Given the above, you certainly could have trouble.
In fact, I don't know how it works in background. In the msdn documentation,
ManualResetEvent.WaitOne() blocks the Thread until it receives a signal.
That's correct.
But
I hope this is not really the case and the Thread is reused in background to
run some other jobs because if I have more than 25 waiting threads in the
queue my app is dead.
Unfortunately, hoping for something doesn't make it true. .NET does not release a thread pool thread back to the pool just because your code has called WaitHandle.WaitOne(). The thread will indeed simply block and remain unavailable for further processing.
The thread pool is significantly larger than 25 threads in .NET 2.0 and later. But, you are right...there is still the potential for a problem. You'd just need a lot more waiting threads to run into it with more recent versions of .NET.
In general, it's not a good idea to block in a thread pool thread. Thread pool threads are for reasonably short tasks that can be completed straight through. If you need a thread that can block for an arbitrarily long amount of time, create a new thread for that purpose rather than using the thread pool.
Is ManualResetEvent.WaitOne() really blocking a Thread or is there any job
in the ThreadPool to let those waiting Threads not block all others in the
queue ?
The former. The code you posted is, at least at its most basic, a good example of how one can deadlock the thread pool. If all those thread pool threads are all blocked waiting on something to happen, and that something isn't going to happen until a newly assigned thread pool task executes, then since that new task will never execute, you'll never get anywhere.
You can correct this by changing the design so that either you have some way to unblock the threads without running a new thread pool task, or you simply move the blocking threads out of the thread pool altogether.
A third alternative would be to make sure you never consume the thread pool completely with threads that could block in that way. That third solution isn't quite as reliable, since you could have other consumers of the thread pool doing the same sort of thing, resulting in all the consumers still managing to consume the thread pool entirely, without any threads that would unblock the threads being allowed to run. So yet another alternative would be to implement your own thread pool, one that you know is used only for this purpose so that you can reliably limit the number of potentially blocking threads, ensuring you've always got at least one thread available that can unblock the blocking threads.
Of course, if all of your threads can theoretically be both blocking and unblocking threads, and if you have no way to determine which they are prior to executing them, this third solution isn't a solution at all. :)
Yet another way to fix it would be to change the design dramatically, providing a way for threads that would otherwise have blocked to simply exit altogether, saving some sort of state so that you can resume executing whatever they were doing at some later point in time when the blocking condition is resolved. That'd be a lot more complicated though. :)
Pete
.
- Follow-Ups:
- Re: Delegate BeginInvoke and ManualResetEvent.WaitOne()
- From: Jon Skeet [C# MVP]
- Re: Delegate BeginInvoke and ManualResetEvent.WaitOne()
- Prev by Date: Re: Async Pages and Thread Pools
- Next by Date: Re: Delegate BeginInvoke and ManualResetEvent.WaitOne()
- Previous by thread: Visual Studio Comment Hiding
- Next by thread: Re: Delegate BeginInvoke and ManualResetEvent.WaitOne()
- Index(es):