473,509 Members | 2,890 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

ThreadPool, ManualResetEvent and WaitOne()

The following is from a simple Windows application in VS2005, which has
button1 and textbox1 dragged onto a form.

In StartThreads(), I call ThreadPool.QueueUserWorkItem(), then call
WaitOne(). My expectation is that I would see the text generated in
WasteTime() before seeing the "Hey" printout that comes after WaitOne().
Instead, I'm seeing the "Hey" as the first thing to print out in the text
box.

Any thoughts on why WaitOne() isn't waiting for the ThreadPool thread to
complete?

Thanks...


private void button1_Click(object sender, EventArgs e)
{
StartThreads();
}

private void StartThreads()
{
CalculationRequest cr = new CalculationRequest();
cr.UserID = "42";

ThreadPool.QueueUserWorkItem(new WaitCallback(WasteTime), cr);

cr.ProcessingEvent.WaitOne();

textBox1.Text += "Hey";
textBox1.Text += "\r\n";
}

private void WasteTime(object state)
{
if (state is CalculationRequest)
{
CalculationRequest cr = state as CalculationRequest;
cr.ProcessingEvent.Set();

for (int i = 0; i < 5; i++)
{
SetText(String.Format("threadId: {0}, count: {1}",
cr.UserID, i));
System.Threading.Thread.Sleep(100);
}

}
}

//The following allows us to set text in textbox1 from a
//ThreadPool thread.
delegate void SetTextCallback(string text);
private void SetText(string text)
{
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text += String.Format("{0}\n", text);
this.textBox1.Text += "\r\n";
}
}
class CalculationRequest
{
public string UserID;

// Thead/Sync info
public ManualResetEvent ProcessingEvent = new
ManualResetEvent(false);
}

Jun 27 '08 #1
7 7177
On Jun 20, 5:41*pm, rbDeveloper
<rbDevelo...@discussions.microsoft.comwrote:
The following is from a simple Windows application in VS2005, which has
button1 and textbox1 dragged onto a form.

In StartThreads(), I call ThreadPool.QueueUserWorkItem(), then call
WaitOne(). My expectation is that I would see the text generated in
WasteTime() before seeing the "Hey" printout that comes after WaitOne().
Why? WaitOne() will only wait until the ManualResetEvent is set, which
it is very early in the threadpool thread. If you move the call to Set
to the *end* of the threadpool operation, you'll see a difference.
However, I predict that it won't be the difference you want. I predict
it will hang.

Your main UI thread is blocking until the threadpool thread sets the
event - but the threadpool thread itself will block while the main
thread isn't processing the message loop, due to your use of
Control.Invoke. I suggest you change that Invoke call to BeginInvoke.
I also suggest you try a different way of handling the whole
situation, probably with a callback at the end of the threadpool
method. After all, if you're going to block the UI thread until
something else has finished, you might as well not be using a
threadpool thread in the first place.

Jon
Jun 27 '08 #2
On Fri, 20 Jun 2008 09:41:01 -0700, rbDeveloper
<rb*********@discussions.microsoft.comwrote:
[...]
Any thoughts on why WaitOne() isn't waiting for the ThreadPool thread to
complete?
Well, the immediate answer to that question is: because you are setting
the event before the thread completes.

It's hard to understand from the code you posted why you would expect it
to wait, given that the first thing you do in your thread is to set the
event.

That said, it's a very very bad idea to be waiting for the thread anyway.
Not only are you waiting in the GUI thread, which makes the GUI
unresponsive, but you've created a deadlock situation by blocking your GUI
thread at the same time that you're using Invoke() from another thread.
If you changed the code so that you didn't set the event before calling
Invoke(), then the GUI thread would be waiting for the worker thread while
the worker thread was waiting for the GUI thread.

Hopefully you see how that won't work. :)

Pete
Jun 27 '08 #3
"Jon Skeet [C# MVP]" wrote:
Why? WaitOne() will only wait until the ManualResetEvent is set, which
it is very early in the threadpool thread. If you move the call to Set
to the *end* of the threadpool operation, you'll see a difference.
However, I predict that it won't be the difference you want. I predict
it will hang.
Hang is exactly what happens when moving set to the end with no other changes.
Your main UI thread is blocking until the threadpool thread sets the
event - but the threadpool thread itself will block while the main
thread isn't processing the message loop, due to your use of
Control.Invoke. I suggest you change that Invoke call to BeginInvoke.
I've changed to start the process on a backgroundworker thread, moved set to
the end, and changed Invoke to BeginInvoke. More importantly, I have a
clearer understanding of how using BeginInvoke and a ThreadPool works.

Many, many thanks for both Jon and Pete. Updated code below in case anyone
reading this wants to review.

Thanks again!
Randy


private void button1_Click(object sender, EventArgs e)
{
_BackgroundWorker.RunWorkerAsync();
}

private void _BackgroundWorker_DoWork(object sender, DoWorkEventArgs
e)
{
StartThreads();
}

private void StartThreads()
{
CalculationRequest cr = new CalculationRequest();
cr.UserID = "42";

ThreadPool.QueueUserWorkItem(new WaitCallback(WasteTime), cr);

cr.ProcessingEvent.WaitOne();

SetText("Hey");
SetText("\r\n");
}

private void WasteTime(object state)
{
if (state is CalculationRequest)
{
CalculationRequest cr = state as CalculationRequest;
for (int i = 0; i < 5; i++)
{
SetText(String.Format("threadId: {0}, count: {1}",
cr.UserID, i));
System.Threading.Thread.Sleep(100);
}
cr.ProcessingEvent.Set();
}
}

//The following allows us to set text in textbox1 from a
//ThreadPool thread.
delegate void SetTextCallback(string text);
private void SetText(string text)
{
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
//this.Invoke(d, new object[] { text });
this.BeginInvoke(d, new object[] { text });
}
else
{
this.textBox1.Text += String.Format("{0}\n", text);
this.textBox1.Text += "\r\n";
}
}
class CalculationRequest
{
public string UserID;

// Thead/Sync info
public ManualResetEvent ProcessingEvent = new
ManualResetEvent(false);
}
Jun 27 '08 #4
rbDeveloper <rb*********@discussions.microsoft.comwrote:
Why? WaitOne() will only wait until the ManualResetEvent is set, which
it is very early in the threadpool thread. If you move the call to Set
to the *end* of the threadpool operation, you'll see a difference.
However, I predict that it won't be the difference you want. I predict
it will hang.

Hang is exactly what happens when moving set to the end with no other changes.
Right - as expected.
Your main UI thread is blocking until the threadpool thread sets the
event - but the threadpool thread itself will block while the main
thread isn't processing the message loop, due to your use of
Control.Invoke. I suggest you change that Invoke call to BeginInvoke.

I've changed to start the process on a backgroundworker thread, moved set to
the end, and changed Invoke to BeginInvoke. More importantly, I have a
clearer understanding of how using BeginInvoke and a ThreadPool works.
However, you've still got a wait in the UI thread. While you're waiting
for the background threads to run, your UI will be useless. You won't
be able to resize it, if windows are moved over it the window won't be
repainted, etc. It's just not a nice thing to do.

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Jun 27 '08 #5
Hi Jon,

Again, all your fantastic insights are greatly appreciated.

I believe control gets returned to the UI because the whole process is now
kicked off on a backgroundworker thread. Responsiveness returns immediately,
repainting is okay, etc. The only thing changed in the code below is that the
thread now runs for 7.5 seconds - long enough to roll other windows over.

Any insights you have area always appreciated.

Randy

private void button1_Click(object sender, EventArgs e)
{
_BackgroundWorker.RunWorkerAsync();
}

private void _BackgroundWorker_DoWork(object sender, DoWorkEventArgs
e)
{
StartThreads();
}

private void StartThreads()
{
CalculationRequest cr = new CalculationRequest();
cr.UserID = "42";

ThreadPool.QueueUserWorkItem(new WaitCallback(WasteTime), cr);

//WaitOne() until the ManualResetEvent is Set.
cr.ProcessingEvent.WaitOne();

SetText("Hey");
SetText("\r\n");
}

private void WasteTime(object state)
{
if (state is CalculationRequest)
{
CalculationRequest cr = state as CalculationRequest;

for (int i = 0; i < 15; i++)
{
SetText(String.Format("threadId: {0}, count: {1}",
cr.UserID, i));
System.Threading.Thread.Sleep(500);
}
//Set the ManualResetEvent();
cr.ProcessingEvent.Set();
}
}

//The following allows us to set text in textbox1 from a
//ThreadPool thread.
delegate void SetTextCallback(string text);
private void SetText(string text)
{
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
//this.Invoke(d, new object[] { text });
this.BeginInvoke(d, new object[] { text });
}
else
{
this.textBox1.Text += String.Format("{0}\n", text);
this.textBox1.Text += "\r\n";
}
}
class CalculationRequest
{
public string UserID;

// Thead/Sync info
public ManualResetEvent ProcessingEvent = new
ManualResetEvent(false);
}
Jun 27 '08 #6
rbDeveloper <rb*********@discussions.microsoft.comwrote:
Again, all your fantastic insights are greatly appreciated.

I believe control gets returned to the UI because the whole process is now
kicked off on a backgroundworker thread.
Ah, I do apologise - I'd missed that. Yes, that should be fine. Serves
me right for not reading closely enough.

However, I'm not sure I see the point of creating a BackgroundWorker
which then just hangs around waiting for something else. Can't you get
the threadpool thread to do the bit of work that needs to happen just
after it's completed the main job? If it makes the code a lot easier,
that's fine - but you may find it trickier to debug 3 threads than 2,
if it ever comes to that...

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Jun 27 '08 #7
On Fri, 20 Jun 2008 13:00:00 -0700, rbDeveloper
<rb*********@discussions.microsoft.comwrote:
Hi Jon,

Again, all your fantastic insights are greatly appreciated.

I believe control gets returned to the UI because the whole process is
now
kicked off on a backgroundworker thread. Responsiveness returns
immediately,
repainting is okay, etc. The only thing changed in the code below is
that the
thread now runs for 7.5 seconds - long enough to roll other windows over.
As Jon suggested, having a BackgroundWorker just sit there and wait for a
thread pool to finish seems sort of wasteful.

In fact, it seems to me that the best implementation would be to simply
have the BackgroundWorker itself do all of the work. That's what it's
for. Don't call "StartThreads()" in the DoWork event handler, just call
"WasteTime()". Then, subscribe a method to the BackgroundWorker's
RunWorkerCompleted event. Assuming you created the BackgroundWorker on
your GUI thread, the RunWorkerCompleted event handler itself will be
executed on your GUI thread, and you won't have to worry about using
Control.Invoke() or Control.BeginInvoke() at all.

As an example (I'm assuming you set up the RunWorkerCompleted event
handler as you do the DoWork handler):

private void button1_Click(object sender, EventArgs e)
{
_BackgroundWorker.RunWorkerAsync();
}

private void _BackgroundWorker_DoWork(object sender,
DoWorkEventArgs e)
{
CalculationRequest cr = new CalculationRequest();
cr.UserID = "42";

WasteTime(cr);
}

private void _BackgroundWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
SetText("Hey");
SetText("\r\n");
}

private void WasteTime(CalculationRequest cr)
{
for (int i = 0; i < 15; i++)
{
SetText(String.Format("threadId: {0}, count: {1}",
cr.UserID, i));
System.Threading.Thread.Sleep(500);
}
}

private void SetText(string text)
{
this.textBox1.Text += String.Format("{0}\n", text);
this.textBox1.Text += "\r\n";
}

class CalculationRequest
{
public string UserID;
}

BackgroundWorker can pass an object to the DoWork event handler if you
want the button click code to do some of the initialization. Basically,
it offers all of the features of directly using the thread pool, but adds
the cross-thread marshalling for the appropriate events (it also has a
ProgressChanged event that is also raised on the GUI thread).

Hope that helps.

Pete
Jun 27 '08 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
14506
by: Kovan Akrei | last post by:
Hi, I would love to know if it is possible some how to ensure that a thread T1 does not call T2.myResetEvent.Set() before T1 has blocked by calling T1.myResetEvent.WaitOne()? I cant use monitors...
1
2298
by: Pujo Aji | last post by:
Hello, I use ManualResetEvent to stop and allow a thread running by setting: public static ManualResetEvent mre = new ManualResetEvent(false); So if I use mre.WaitOne(); this let the thread...
0
1412
by: Mark | last post by:
Hi, How do I stop a ManualResetEvent.WaitOne from intermittently jumping to 0? I am using version 1.1 of the framework. My ManualResetEvent instance is named "bev". To make the WaitOne work...
3
12585
by: Elhurzen | last post by:
X-No-Archive: Yes >From what I understand, if multiple threads are waiting on a ManualResetEvent after calling WaitOne(), only one thread is guaranteed to be signaled when Set() is called on that...
10
5564
by: Shad | last post by:
Hello, here's my problem (I've been searching for a fews days already and couldn't find a solution) I've got a bunch of mails to create, so I'd like to queue jobs in a threadpool (which I can...
0
1157
by: TY | last post by:
Hi Everyone, I have a multithreading application, a typical Main thread that uses the ThreadPool.QueueUserWorkItem method to add new threads to the Thread POOL. I need a way to control the...
2
3449
by: James | last post by:
i uses the above to send some thread to many machines and perform a ping and return results to my event log Is there a way to determine when the *last* thread returns, and i can terminate my...
5
2555
by: =?Utf-8?B?RkxEYXZlTQ==?= | last post by:
I'm developing an application that gets data from 100 sources (via telnet connections, but you can think stock quotes from a webservice if you like). I was planning on using the thread pool (25...
15
2903
by: Peter Larsen [] | last post by:
Hi, I have a problem using a ManuelResetEvent in the GUI thread while receiving events from the Shell (new folders, rename etc). This is what i do: Receiving an event from the Shell....
0
7136
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7344
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
1
7069
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
1
5060
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
4730
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3216
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
3203
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1570
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
1
775
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.