thread.join causing me pain

G

Guest

Hello All, I have created a very simple C# windows forms application that
processes some computations from data retrieved over a network from machines
that have fast and some that have very slow network connections. The
computations will update the main windows form (main). In order to allow the
main form to be updated without freezing I have created a seperate thread to
do the computations. From within main() I start the computation thread.

Thread oThread = new Thread(BeginComputation);
oThread.start();

BeginComputation()
{
do work;
.....
}

I would like to wait for the BeginComputation code to complete before
continuing on in the main() function. I have tried using Join() but it just
hangs up the windows form (i.e. looks like program stops responding).

Thread oThread = new Thread(BeginComputation);
oThread.start();
oThread.join(); //this causes app to freeze

Please help me so that I can wait for BeginComputation to finish and then
continue on in main() function.

Thanks,
Josh
 
N

Nicholas Paldino [.NET/C# MVP]

Josh,

Instead of calling Join, in the end of the BeginComputation method, make
a call to Invoke on the main form, passing a delegate which will begin the
work to update the UI.

When you call Join (which you shouldn't really do anyways) it waits for
the thread to complete. If you call this on your UI thread, then the UI
thread can't process windows messages, and results in the hangup that you
see.
 
P

Peter Duniho

Nicholas said:
[...]
When you call Join (which you shouldn't really do anyways) it waits for
the thread to complete. If you call this on your UI thread, then the UI
thread can't process windows messages, and results in the hangup that you
see.

In other words (just to rephrase what Nicholas wrote): when you use
Join, you negate the whole point of putting your code in a different
thread in the first place.

Don't do that.

Pete
 
G

Guest

Would you be willing to provide a quick example of how to implement what you
mean?

Nicholas Paldino said:
Josh,

Instead of calling Join, in the end of the BeginComputation method, make
a call to Invoke on the main form, passing a delegate which will begin the
work to update the UI.

When you call Join (which you shouldn't really do anyways) it waits for
the thread to complete. If you call this on your UI thread, then the UI
thread can't process windows messages, and results in the hangup that you
see.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

JoshP said:
Hello All, I have created a very simple C# windows forms application that
processes some computations from data retrieved over a network from
machines
that have fast and some that have very slow network connections. The
computations will update the main windows form (main). In order to allow
the
main form to be updated without freezing I have created a seperate thread
to
do the computations. From within main() I start the computation thread.

Thread oThread = new Thread(BeginComputation);
oThread.start();

BeginComputation()
{
do work;
....
}

I would like to wait for the BeginComputation code to complete before
continuing on in the main() function. I have tried using Join() but it
just
hangs up the windows form (i.e. looks like program stops responding).

Thread oThread = new Thread(BeginComputation);
oThread.start();
oThread.join(); //this causes app to freeze

Please help me so that I can wait for BeginComputation to finish and then
continue on in main() function.

Thanks,
Josh
 
G

Guest

As I read the response further, I am already using Invoke to update the
listbox control on the main form. The problem is not updating the main form
from another thread; it is how to wait for the computation to complete before
moving on with Main()

Example:

oThread = new Thread(PreFlightCheck);
oThread.Name = "PreFlightCheck Worker Thread";
oThread.Start();
//stop here and wait for PreFlightCheck() to finish before moving on.

CodeToRunAfter();



JoshP said:
Would you be willing to provide a quick example of how to implement what you
mean?

Nicholas Paldino said:
Josh,

Instead of calling Join, in the end of the BeginComputation method, make
a call to Invoke on the main form, passing a delegate which will begin the
work to update the UI.

When you call Join (which you shouldn't really do anyways) it waits for
the thread to complete. If you call this on your UI thread, then the UI
thread can't process windows messages, and results in the hangup that you
see.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

JoshP said:
Hello All, I have created a very simple C# windows forms application that
processes some computations from data retrieved over a network from
machines
that have fast and some that have very slow network connections. The
computations will update the main windows form (main). In order to allow
the
main form to be updated without freezing I have created a seperate thread
to
do the computations. From within main() I start the computation thread.

Thread oThread = new Thread(BeginComputation);
oThread.start();

BeginComputation()
{
do work;
....
}

I would like to wait for the BeginComputation code to complete before
continuing on in the main() function. I have tried using Join() but it
just
hangs up the windows form (i.e. looks like program stops responding).

Thread oThread = new Thread(BeginComputation);
oThread.start();
oThread.join(); //this causes app to freeze

Please help me so that I can wait for BeginComputation to finish and then
continue on in main() function.

Thanks,
Josh
 
N

Nicholas Paldino [.NET/C# MVP]

Josh,

That's the thing, you can't. If you were going to wait, you would have
to spin a message loop in your code at that point so you could process other
messages on the UI thread. Of course, you could do that with DoEvents, but
that's really bad practice in this case.

So, you have to break your algorithm into multiple methods. Basically,
you are going to do something like this:

- Call initial method on UI thread.
- Method spawns new thread, continues processing on that thread.
- Thread routine does work, calls Invoke, calling method to continue where
initial method left off.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

JoshP said:
As I read the response further, I am already using Invoke to update the
listbox control on the main form. The problem is not updating the main
form
from another thread; it is how to wait for the computation to complete
before
moving on with Main()

Example:

oThread = new Thread(PreFlightCheck);
oThread.Name = "PreFlightCheck Worker Thread";
oThread.Start();
//stop here and wait for PreFlightCheck() to finish before moving on.

CodeToRunAfter();



JoshP said:
Would you be willing to provide a quick example of how to implement what
you
mean?

Nicholas Paldino said:
Josh,

Instead of calling Join, in the end of the BeginComputation method,
make
a call to Invoke on the main form, passing a delegate which will begin
the
work to update the UI.

When you call Join (which you shouldn't really do anyways) it waits
for
the thread to complete. If you call this on your UI thread, then the
UI
thread can't process windows messages, and results in the hangup that
you
see.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Hello All, I have created a very simple C# windows forms application
that
processes some computations from data retrieved over a network from
machines
that have fast and some that have very slow network connections. The
computations will update the main windows form (main). In order to
allow
the
main form to be updated without freezing I have created a seperate
thread
to
do the computations. From within main() I start the computation
thread.

Thread oThread = new Thread(BeginComputation);
oThread.start();

BeginComputation()
{
do work;
....
}

I would like to wait for the BeginComputation code to complete before
continuing on in the main() function. I have tried using Join() but
it
just
hangs up the windows form (i.e. looks like program stops responding).

Thread oThread = new Thread(BeginComputation);
oThread.start();
oThread.join(); //this causes app to freeze

Please help me so that I can wait for BeginComputation to finish and
then
continue on in main() function.

Thanks,
Josh
 
G

Guest

If I call another method to continue where I left off; won't the non-main
thread be running the code in the new method? How would I ever transfer
control back to the main thread?

Nicholas Paldino said:
Josh,

That's the thing, you can't. If you were going to wait, you would have
to spin a message loop in your code at that point so you could process other
messages on the UI thread. Of course, you could do that with DoEvents, but
that's really bad practice in this case.

So, you have to break your algorithm into multiple methods. Basically,
you are going to do something like this:

- Call initial method on UI thread.
- Method spawns new thread, continues processing on that thread.
- Thread routine does work, calls Invoke, calling method to continue where
initial method left off.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

JoshP said:
As I read the response further, I am already using Invoke to update the
listbox control on the main form. The problem is not updating the main
form
from another thread; it is how to wait for the computation to complete
before
moving on with Main()

Example:

oThread = new Thread(PreFlightCheck);
oThread.Name = "PreFlightCheck Worker Thread";
oThread.Start();
//stop here and wait for PreFlightCheck() to finish before moving on.

CodeToRunAfter();



JoshP said:
Would you be willing to provide a quick example of how to implement what
you
mean?

:

Josh,

Instead of calling Join, in the end of the BeginComputation method,
make
a call to Invoke on the main form, passing a delegate which will begin
the
work to update the UI.

When you call Join (which you shouldn't really do anyways) it waits
for
the thread to complete. If you call this on your UI thread, then the
UI
thread can't process windows messages, and results in the hangup that
you
see.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Hello All, I have created a very simple C# windows forms application
that
processes some computations from data retrieved over a network from
machines
that have fast and some that have very slow network connections. The
computations will update the main windows form (main). In order to
allow
the
main form to be updated without freezing I have created a seperate
thread
to
do the computations. From within main() I start the computation
thread.

Thread oThread = new Thread(BeginComputation);
oThread.start();

BeginComputation()
{
do work;
....
}

I would like to wait for the BeginComputation code to complete before
continuing on in the main() function. I have tried using Join() but
it
just
hangs up the windows form (i.e. looks like program stops responding).

Thread oThread = new Thread(BeginComputation);
oThread.start();
oThread.join(); //this causes app to freeze

Please help me so that I can wait for BeginComputation to finish and
then
continue on in main() function.

Thanks,
Josh
 
P

Peter Duniho

JoshP said:
As I read the response further, I am already using Invoke to update the
listbox control on the main form.

If you use Control.Invoke(), how does your background thread get past
that call? Since your main form thread is blocked, it should not be
able to service the Invoke(), which means the background thread will
also get stuck calling Invoke().
The problem is not updating the main form
from another thread; it is how to wait for the computation to complete before
moving on with Main()

As Nicholas said, you can't. That's completely antithetical to the
whole point of using a background worker in the first place.

Also, you keep talking about this "Main" method. But in a forms
application, a form is not usually even created until after all of the
interesting code in Main() has executed. Then the form itself would do
things, such as starting background threads, presenting the UI, etc.

I think that rather than asking for Nicholas or someone else to provide
some sample code that will solve your problem, the first thing to do is
for YOU to provide a concise-but-complete example of code that
demonstrates the issue you're having. You haven't posted any code that
would be useful for talking about how to best solve your problem, and
the lack of such code makes it very difficult to do anything except
explain the impossibilities of what you're asking to do.

If you want better information about what you CAN do, you need to
provide more detailed information regarding what you're doing now, and
how that doesn't work for you.

Please note that in "concise-but-complete", both words are important.
Don't post code that isn't directly related to demonstrating the issue,
but also make sure to post a complete program that can be compiled
without any additional effort on our part (other than copying it
somewhere that it can be compiled, of course).

Pete
 
N

Nicholas Paldino [.NET/C# MVP]

Josh,

You are spawning your new thread from the UI thread, right? From the
new thread, you can call Invoke, and it will make the call on the UI thread.

Also, if the call to Invoke is going to occur at the end of the routine
for the background worker thread, then you can call BeginInvoke, and marshal
the call to the UI thread. This will allow the thread to die off.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

JoshP said:
If I call another method to continue where I left off; won't the non-main
thread be running the code in the new method? How would I ever transfer
control back to the main thread?

Nicholas Paldino said:
Josh,

That's the thing, you can't. If you were going to wait, you would
have
to spin a message loop in your code at that point so you could process
other
messages on the UI thread. Of course, you could do that with DoEvents,
but
that's really bad practice in this case.

So, you have to break your algorithm into multiple methods.
Basically,
you are going to do something like this:

- Call initial method on UI thread.
- Method spawns new thread, continues processing on that thread.
- Thread routine does work, calls Invoke, calling method to continue
where
initial method left off.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

JoshP said:
As I read the response further, I am already using Invoke to update the
listbox control on the main form. The problem is not updating the main
form
from another thread; it is how to wait for the computation to complete
before
moving on with Main()

Example:

oThread = new Thread(PreFlightCheck);
oThread.Name = "PreFlightCheck Worker Thread";
oThread.Start();
//stop here and wait for PreFlightCheck() to finish before moving on.

CodeToRunAfter();



:

Would you be willing to provide a quick example of how to implement
what
you
mean?

:

Josh,

Instead of calling Join, in the end of the BeginComputation
method,
make
a call to Invoke on the main form, passing a delegate which will
begin
the
work to update the UI.

When you call Join (which you shouldn't really do anyways) it
waits
for
the thread to complete. If you call this on your UI thread, then
the
UI
thread can't process windows messages, and results in the hangup
that
you
see.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Hello All, I have created a very simple C# windows forms
application
that
processes some computations from data retrieved over a network
from
machines
that have fast and some that have very slow network connections.
The
computations will update the main windows form (main). In order
to
allow
the
main form to be updated without freezing I have created a seperate
thread
to
do the computations. From within main() I start the computation
thread.

Thread oThread = new Thread(BeginComputation);
oThread.start();

BeginComputation()
{
do work;
....
}

I would like to wait for the BeginComputation code to complete
before
continuing on in the main() function. I have tried using Join()
but
it
just
hangs up the windows form (i.e. looks like program stops
responding).

Thread oThread = new Thread(BeginComputation);
oThread.start();
oThread.join(); //this causes app to freeze

Please help me so that I can wait for BeginComputation to finish
and
then
continue on in main() function.

Thanks,
Josh
 
D

dvestal

Josh,

When you call Join (which you shouldn't really do anyways)...

Is calling "Join" bad design? Or were you saying that in the context
of Josh's example, it would probably not be good?

I wasn't aware of a problem with Join.
 
P

Peter Duniho

Is calling "Join" bad design? Or were you saying that in the context
of Josh's example, it would probably not be good?

I wasn't aware of a problem with Join.

There's nothing inherently bad about Join(). I definitely wouldn't put
it into the same category of bad ideas as, for example, DoEvents(). But
it is true that if you find yourself using Join(), usually that's a sign
that you've got a useless thread.

Put another way, if you can afford to call Join() and make one thread
wait on one or more other threads, then what is the point of having that
thread in the first place?

If you are waiting on just one thread, that's the best example of bad
design, since obviously you could just do whatever it is that's put into
the other thread in the original thread, and the net effect would be the
same.

But even if you're waiting on multiple threads, what's the point of
having a thread just sit and stop while a bunch of other threads do
stuff? In most cases, it would be better to implement a different
design in which the last working thread that completes handles whatever
it is that blocked thread would be doing.

It is true that in some cases, using Join() is a simpler way to
accomplish an intended behavior. So I won't say that it's never needed.

But you would definitely not want to call Join() in a thread that you
need to not stop (like the UI thread), and you would definitely not want
to call Join() just to wait on a single other thread. The example here
appears to violate both of those rules.

Pete
 
N

Nicholas Paldino [.NET/C# MVP]

Calling Join is generally bad practice, as it is usually tied to an OS
thread, which Thread is not (it is a logical representation of a thread).

In favor of Join, one should use other synchronization methods, like
Events.
 
N

Nicholas Paldino [.NET/C# MVP]

Let me elaborate a little bit. In calling Join, you are taking the
threading decisions out of the CLR host's hands (as indicated by the
HostProtection attribute applied to the Join method).

This is important if you are writing code that is going to be used in a
CLR environment outside of an application (if it is hosted in SQL Server,
for example). If not, then it's not really an issue.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Nicholas Paldino said:
Calling Join is generally bad practice, as it is usually tied to an OS
thread, which Thread is not (it is a logical representation of a thread).

In favor of Join, one should use other synchronization methods, like
Events.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Is calling "Join" bad design? Or were you saying that in the context
of Josh's example, it would probably not be good?

I wasn't aware of a problem with Join.
 
G

Guest

Peter, please excuse the rest of us less experienced programmers from
attempting to ask professionals such as yourself a question the best way I
can. I am trying to solve a problem to better myself at programming. I use
MSDN groups because I usually have courteous responses (without Uppercase
emphasis on words) from the many good programmers here. I have not provided
specific examples from the program I am writing because it would not compile
(and run) on anyone's computer without having internal parts of the
application (i.e. network locations, etc.).

I tried giving an example to the best of my ability. Please don't fault me
for using Main(), I was shortening the form names load event. Again, the
root issues I am trying to resolve is that I want to run a series of
computations. At the same time these computations are running, I want a
listbox that is constantly updating to reflect the activity of each set of
computations without the main form from blocking UI controls and rendering.
So I figured if I used a second thread to process the computations the main
form (and listbox) could be updated without issue (i.e. the form would not be
unresponsive and I could watch listbox activities in real time). I basically
don't have an issue with executing the first computation, but I do have an
issue where I would like a second computation to run only after the first
completes (and I don't want the worker thread to execute the second
computation). I was hoping that someone would have ideas and would be
willing to share them (and once again, I appeared to have caused you to get a
irratated somehow). Please excuse me for that....I am not that experienced
of a programmer, but don't fault me for trying to learn.
 
P

Peter Duniho

willing to share them (and once again, I appeared to have caused you to get a irratated somehow). Please excuse me for that....I am not that experienced of a programmer, but don't fault me for trying to learn.

I have quoted the last part of your post first, because it demonstrates
a misunderstanding. I don't know why you think I'm irritated; I'm not.
However, the fact is that you haven't presented your question in a way
that would best serve your interests.

You need to remember: every answer provided here is strictly on a
volunteer basis. The more work you make someone else do in order to try
to understand and answer your question, the less likely it is your
question will be answered.

Beyond that, there are simply some minimum requirements that are
necessary in order to receive a correct or useful answer, and your
original post doesn't really meet those requirements. I have tried to
help you understand what those requirements are. You seem to think that
someone trying to help you means that they are irritated with you. How
you come to that conclusion is a mystery to me, but suffice to say it's
the wrong conclusion.

Now, for the rest of your post...
Peter, please excuse the rest of us less experienced programmers from
attempting to ask professionals such as yourself a question the best way I
can. I am trying to solve a problem to better myself at programming. I use
MSDN groups because I usually have courteous responses (without Uppercase
emphasis on words) from the many good programmers here.

I have been nothing but courteous. Any perception on your part
otherwise is due to your misunderstanding, not lack of courtesy.
I have not provided
specific examples from the program I am writing because it would not compile
(and run) on anyone's computer without having internal parts of the
application (i.e. network locations, etc.).

That is the point of asking for a concise-but-complete sample. Of
course you should not post your whole program, for the reasons you state
and others.

But the fact is, most of the stuff in your program has absolutely
nothing to do with the problem you're asking about. Even the specific
calculation is not meaningful; you could (and should) replace that code
in a sample with some placeholder, like a call to Thread.Sleep()
specifying a time that is similar to that your calculations normally take.

Likewise the rest of the logic that is relevant to your program. Create
a new sample program that incorporates all of the relevant logic, and
nothing else.

Yes, this is more work for you. However, a) you will learn a great deal
in making such an example, and in fact oftentimes a person will discover
the answer to their own question by removing all the clutter from the
basic problem, and b) it is futile for us to try to figure out what your
program does without any code to read. Only in the simplest cases does
it suffice to describe in English the operation of the code. This is
definitely not a simple case.
I tried giving an example to the best of my ability. Please don't fault me
for using Main(), I was shortening the form names load event.

I must fault you, because using the name of a method that has a very
specific meaning in the context of a .NET/C# program is EXTREMELY
misleading. If you will not provide an actual code sample, you must at
least ensure that you only describe your code in unambiguous terms, and
definitely not using terms that already have very specific meaning in
this context but which are not the meaning you intend.

I appreciate the clarification, but the solution is to not use the wrong
terminology in the first place. It's a valid criticism of your post,
and rather than being defensive about it, you should simply accept the
criticism, comprehend why it's valid, and move on (avoiding the
repetition of the mistake in the future, of course).
Again, the
root issues I am trying to resolve is that I want to run a series of
computations. At the same time these computations are running, I want a
listbox that is constantly updating to reflect the activity of each set of
computations without the main form from blocking UI controls and rendering.

That describes a very basic technique, one that has been explained many
times in this newsgroup. The basic idea is to create the thread and use
Invoke() to interact with the Listbox instance. You'll find many
examples and discussions on the technique if you search the newsgroup
using Google Groups.

However, using that technique you would not use the Join() method. As
has been stated several times already, Join() defeats the entire purpose
of putting your computations in a separate thread. Don't use Join().
So I figured if I used a second thread to process the computations the main
form (and listbox) could be updated without issue (i.e. the form would not be
unresponsive and I could watch listbox activities in real time). I basically
don't have an issue with executing the first computation, but I do have an
issue where I would like a second computation to run only after the first
completes (and I don't want the worker thread to execute the second
computation).

This is the first time I have seen you say anything about wanting to
perform a second computation after the first completes. This is a key
piece of information regarding your question that you've left out up to
this point.

Now, with that information, we can provide a more useful answer to you:

You still do not need to call Join(). It's not at all clear to me the
point of your objection to continuing in the worker thread after the
first computation, to go on and do the second. However, assuming that's
a valid requirement, you have at least two options:

1) Notify the form via some mechanism that the first computation
thread has completed, at which point the form will start the second
computation thread. The easiest way to do this would be to define a
method on the form that will do this.

You can either use Invoke() to call the method (this would be required
if the code starting the second computation thread needs access to
something in the base Form class), or you could just call the method
directly. In the latter case, this is not much different from your
second option, which is...

2) In the first computation thread, simply start the second
computation thread before exiting.

Either technique will work fine, and neither requires the use of the
Join() method.

Personally, I prefer using the BackgroundWorker class for stuff like
this. In the class you add handlers for the DoWork and
RunWorkerCompleted events, where the DoWork handler performs your
computation, and the RunWorkerCompleted handler does whatever you want
done upon completion of the work (including starting a new computation
if desired). The nice thing about BackgroundWorker is that the
RunWorkerCompleted event is automatically executed on the same thread
that created the BackgroundWorker, so if you have some Form-dependent
stuff you don't need to bother calling Invoke(). You'll already be
handling the event on the correct thread.
I was hoping that someone would have ideas and would be
willing to share them (and once again, I appeared to have caused you to get a
irratated somehow). Please excuse me for that....I am not that experienced
of a programmer, but don't fault me for trying to learn.

No one is faulting you for trying to learn. But if you are actually
interested in learning, you also need to be interested in how to best
present your questions. It's very difficult to answer a question that
doesn't accurately or completely describe what the questioner really
wants. Instead, it creates confusion and frustration as the question
that was actually asked is answered, but the questioner comes back and
says "but you didn't answer my question".

What the questioner means is "you didn't answer the question I actually
have", even as it's true that the answerer _did_ in fact answer the
question that was asked.

You need to get past any defensiveness with respect to constructive
criticism, and just understand that these replies are intended to help.
You may be sitting there thinking "well, why don't you just answer my
question instead of hassling me", but the fact is that sometimes the
best way to solve a person's problem is to first work on the techniques
necessary in order to get the person to state the problem in a way that
allows it to be answered.

Basically, no one can answer your question unless they understand it,
and so when we don't understand the question, our first step is to help
you learn how to better state your question. Otherwise, we're just
answering some random question that may or may not have anything to do
with your real question.

Pete
 

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