How to yield the primary thread to some other task?

B

Boris Drajer

Hi,

I'm trying to create a method on my windows form that starts a
multi-threaded task, waits for it to finish, and then returns.

To be more precise: the form has a LoadUrl() method. This method calls
the Navigate() method on the form's embedded WebBrowser control, and
then does a WaitOne() on a ManualResetEvent. This ManualResetEvent will
be Set() from WebBrowser's DocumentComplete handler when loading is done.


So, what happens is this: when Navigate() is called, the web browser
starts the download in a secondary thread and returns, thus jumping to
my WaitOne() call where I wait for it to finish. While downloading, the
browser wants to update the UI, which has to be done from the primary
thread. But no dice, the WaitOne() call is blocking it.

Now, I must do some kind of Wait() on the primary thread because I want
to return from the method only when the operation is complete. But, I
somehow have to wait without blocking this thread. Is this possible?

It seems that the windows form has a solution to this. How does the form
manage this primary thread so it knows how to do BeginInvoke, for
example? Do I need to use the message loop or something?

Any hint is welcome. Thanks in advance!
 
S

Steve Alpert

Boris said:
Hi,

I'm trying to create a method on my windows form that starts a
multi-threaded task, waits for it to finish, and then returns.

To be more precise: the form has a LoadUrl() method. This method calls
the Navigate() method on the form's embedded WebBrowser control, and
then does a WaitOne() on a ManualResetEvent. This ManualResetEvent will
be Set() from WebBrowser's DocumentComplete handler when loading is done.


So, what happens is this: when Navigate() is called, the web browser
starts the download in a secondary thread and returns, thus jumping to
my WaitOne() call where I wait for it to finish. While downloading, the
browser wants to update the UI, which has to be done from the primary
thread. But no dice, the WaitOne() call is blocking it.

Now, I must do some kind of Wait() on the primary thread because I want
to return from the method only when the operation is complete. But, I
somehow have to wait without blocking this thread. Is this possible?

It seems that the windows form has a solution to this. How does the form
manage this primary thread so it knows how to do BeginInvoke, for
example? Do I need to use the message loop or something?

Any hint is welcome. Thanks in advance!
How about DoEvents() until a doneflag is detected?

/steveA
 
J

Jon Skeet [C# MVP]

Boris Drajer said:
I'm trying to create a method on my windows form that starts a
multi-threaded task, waits for it to finish, and then returns.

To be more precise: the form has a LoadUrl() method. This method calls
the Navigate() method on the form's embedded WebBrowser control, and
then does a WaitOne() on a ManualResetEvent. This ManualResetEvent will
be Set() from WebBrowser's DocumentComplete handler when loading is done.


So, what happens is this: when Navigate() is called, the web browser
starts the download in a secondary thread and returns, thus jumping to
my WaitOne() call where I wait for it to finish. While downloading, the
browser wants to update the UI, which has to be done from the primary
thread. But no dice, the WaitOne() call is blocking it.

See http://www.pobox.com/~skeet/csharp/threads/winforms.shtml
Now, I must do some kind of Wait() on the primary thread because I want
to return from the method only when the operation is complete.

That's a really bad idea, because it will make the UI completely block
(no repaints, no moving the window etc). Disable what you need to
disable, but leave the UI thread free.
 
B

Boris Drajer

Yep, that was it... Instead of WaitOne, I did something like:

while(!manualResetEvent.WaitOne(short timeout))
{
DoEvents();
}

What this basically does is a non-thread-blocking wait.

Thanks!
 
S

ShaneB

Check your CPU usage while that loop is running. It will be in the
high-90s. You can significantly decrease down to <10% by placing making the
following change:

while(!manualResetEvent.WaitOne(short timeout))
{

System.Threading.Thread.Sleep(1);
Application.DoEvents();
}

Note that I'd personally use a delegate and Control.Invoke to accomplish
this job. DoEvents can cause reentrant problems if you're not very
careful...so I recommend avoiding it whenever possible.

ShaneB
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top