On Mon, 11 Feb 2008 09:56:01 -0800, Alphapage
<Alphap
...@discussions.microsoft.com> 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