thread

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi,

How do I wait until a thread is finished his job then continue to the
original thread?

public void main(string[] args)
{
Thread t = new Thread(new ThreadStart(DoWork));
t.Start();

while(t.IsAlive)
{
// I don't know how to wait until thread t is done
// then execute MessageBox below. I don't want
// a blank while loop body because it takes up 100%
// of my CPU
}

MessageBox.Show("Bla");
}

private void DoWork()
{
// do more
}

Please advice, thanks!
-P
 
Willy Denoyette said:
t.Start();
t.Join();
// Go on ....

And then you need to ask yourself why you want another thread in the
first place. If you're going to start a thread and then block the
current thread until the new thread has finished, why not just call the
method directly in the original thread?
 
Jon,

I don't have to ask myself, OP should ask :-).
I see many people experimenting with threads these day's, probably to learn
how they work and hopefuly to discover that there is a lot that can be done
without them.

Maybe a better answer would have been...

t.Start();
// if you have something to run in parallel, do it now, else don't use a
thread and call your procedure here.
// finally, If you need the outcome of the thread procedure or you simply
want to be sure the thread procedure finished it's job
// call:
t.Join();

Willy.
 
Another reason to call t.Join() instead of an other "blocking wait" is to
pump messages while waiting for your thread to finish.

Willy.

Willy Denoyette said:
Jon,

I don't have to ask myself, OP should ask :-).
I see many people experimenting with threads these day's, probably to
learn how they work and hopefuly to discover that there is a lot that can
be done without them.

Maybe a better answer would have been...

t.Start();
// if you have something to run in parallel, do it now, else don't use a
thread and call your procedure here.
// finally, If you need the outcome of the thread procedure or you simply
want to be sure the thread procedure finished it's job
// call:
t.Join();

Willy.
 
Willy,
You are not suggesting that if you block the UI thread in Join() the message
pump will keep runing, are you?

--

Stoitcho Goutsev (100) [C# MVP]


Willy Denoyette said:
Another reason to call t.Join() instead of an other "blocking wait" is to
pump messages while waiting for your thread to finish.

Willy.
 
Wil,

I actually run this in my win form. So the complete scenario is that I have
a datagrid and I want to run FillDG() in different thread and once it
finishes, I want to bind the data.

private void button1_Click(object sender, System.EventArgs e)
{
Thread t = new Thread(new ThreadStart(FillDG));
t.Start();

// I need to wait for t to finish
// I tried t.Join(); but this locked up the win form, i.e. I can't move the
form around

myDataGrid.SetDataBinding(myDataSet, "myDataTable");
}

Any idea how?
-P

Willy Denoyette said:
Jon,

I don't have to ask myself, OP should ask :-).
I see many people experimenting with threads these day's, probably to learn
how they work and hopefuly to discover that there is a lot that can be done
without them.

Maybe a better answer would have been...

t.Start();
// if you have something to run in parallel, do it now, else don't use a
thread and call your procedure here.
// finally, If you need the outcome of the thread procedure or you simply
want to be sure the thread procedure finished it's job
// call:
t.Join();

Willy.
 
Stoitcho,

Yes, the CLR will perform a limited amount of pumping when in a
Thread.Join(), the same applies for GC.WaitForPendingFinalizers(1) and some
other managed wait API's like WaitHandle.WaitOne (2). One of the reasons for
this is to prevent the finalizer thread to block when attempting
inter-thread marshaling between the Finalizer thread (MTA) and an STA
thread, in a scenario that the Finalizer needs to Release a COM object
(calling IUnknown::Release on the RCW) that lives in the STA.
Note that UI threads, also running in an STA, don't need this as there is a
lot of pumping going on, but non UI threads running in an STA better pump
messages when hosting COM objects in finalizable objects. Failing to pump
results in a stalled finalizer, a growing number of unreleased COM
references (and resources, like unmanaged memory) and finally a process
crash.

1) Note that GC.WaitForPendingFinalizers also waits for the finalizer queue
to drain.
2) That's one of the reasons not to use the OS synchronization primitives in
managed code.

Willy.

Stoitcho Goutsev (100) said:
Willy,
You are not suggesting that if you block the UI thread in Join() the
message pump will keep runing, are you?

--

Stoitcho Goutsev (100) [C# MVP]


Willy Denoyette said:
Another reason to call t.Join() instead of an other "blocking wait" is to
pump messages while waiting for your thread to finish.

Willy.
 
Hi Willy,

Where did you get that information. I doesn't make any sense to me. If you
have any sources (links, books, articles, etc) I'll appreciate if you post
them here.
See my opinion inlined
Yes, the CLR will perform a limited amount of pumping when in a

CLR cannot perform any pumping simply because the pumping has to be done by
the UI thread itself. It is blocked to perform pumping means that the thread
needs to be unblocked and let executing the code. That is exactly what the
programmer called Join wants to avoid. What if the execution loops back and
executes the same lines of code thus, instantiate and start new thread and
call new Join. If this is possible why one would block the main thread one
simply can let the main thread go.
Once the thread is blocked that's it it is blocked, period.
Thread.Join(), the same applies for GC.WaitForPendingFinalizers(1) and
some other managed wait API's like WaitHandle.WaitOne

(2). One of the reasons for
this is to prevent the finalizer thread to block when attempting
inter-thread marshaling between the Finalizer thread (MTA) and an STA
thread, in a scenario that the Finalizer needs to Release a COM object
(calling IUnknown::Release on the RCW) that lives in the STA.

Indeed. That exactly what happens. The finalizer thread blocks as well as
the thread calling WaitForPandingFinalizers. Deadlock!?! Well, not exactly
because CLR gives certain amount of time for all finalizers to finish. If
some of the finalizers are not executed... well, too bad for them.

There is KB article addressing this issue:
http://support.microsoft.com/default.aspx?scid=kb;en-us;828988
Note that UI threads, also running in an STA, don't need this as there is
a lot of pumping going on, but non UI threads running in an STA better
pump messages when hosting COM objects in finalizable objects.

Non-UI thread doesn't pump because they don't have message queue. That's why
they are called non-UI.
Further more non-UI STA threads cannot host (create) COM objects simply
because STA apartment marshal's via windows messages thus, the thread has to
have message queue (UI thread)
Failing to pump results in a stalled finalizer, a growing number of
unreleased COM references (and resources, like unmanaged memory) and
finally a process crash.

Exactly. That's exactly what happens. That's why if creating COM objects in
STA thread and the object has finalizer that calls Release, don't call
WaitForPandingFinalizers
1) Note that GC.WaitForPendingFinalizers also waits for the finalizer
queue to drain.

Not exactly threre is a timeout.
2) That's one of the reasons not to use the OS synchronization primitives
in managed code.

Well. .NET has enough sync primitives (each of which I believe are based on
OS primitives at the moment)



The bottom line: When the thread is blocked that's it it is blocked, period.
There is no semiblocked threads.
While GC.WaitFor.... and COM object is not easily to verify (fortunately
there is KB article for that) all other sync methods can be tested. Just run
some tests and you'll see there is no pumping.
 
Hi Stoitcho,

I don't want to start a long discussion on this complicated subject before
you did read the sources[1], I'm not sure this can even be discussed in
great detail in a public forum without me breaking some NDA.

See inline ****

Willy.

Stoitcho Goutsev (100) said:
Hi Willy,

Where did you get that information. I doesn't make any sense to me. If you
have any sources (links, books, articles, etc) I'll appreciate if you post
them here.

****
[1] Here are the links, most notably chris brummes blogs will be enlightning
:-)

http://blogs.msdn.com/cbrumme/archive/2004/02/20/77460.aspx

http://blogs.msdn.com/cbrumme/archive/2004/02/20/77460.aspx

http://blogs.msdn.com/maoni/archive/2004/11/04/252697.aspx

Another great source of info are the VM source files, I have access to the
MSFT .NET sources (no, not Rotor) files through the Code Center Premium
license.

and : http://support.microsoft.com/default.aspx?scid=kb;en-us;828988

See my opinion inlined


CLR cannot perform any pumping simply because the pumping has to be done
by the UI thread itself. It is blocked to perform pumping means that the
thread needs to be unblocked and let executing the code. That is exactly
what the programmer called Join wants to avoid. What if the execution
loops back and executes the same lines of code thus, instantiate and start
new thread and call new Join. If this is possible why one would block the
main thread one simply can let the main thread go.
Once the thread is blocked that's it it is blocked, period.
**** Beware the difference between a logical (CLR) and a physical
(OS)thread. The CLR hijacks the UI thread (OS) when calling Join(), this is
not the same as blocking a thread at the OS level. (Note: UI thread here
means a thread with a HWND associated, not necessarily a visible windows)

(2). One of the reasons for

Indeed. That exactly what happens. The finalizer thread blocks as well as
the thread calling WaitForPandingFinalizers. Deadlock!?! Well, not exactly
because CLR gives certain amount of time for all finalizers to finish. If
some of the finalizers are not executed... well, too bad for them.

There is KB article addressing this issue:
http://support.microsoft.com/default.aspx?scid=kb;en-us;828988

**** Did you read the complete article, this is a snip taken from the bottom
of the page:

If you must use STA threads to create COM components, the STA threads must
pump messages regularly. To pump messages for a short time, call the
Thread.Join method, as follows:
Thread.CurrentThread.Join(100)This method call pumps messages for 100
milliseconds. You can adjust the time-out based on the requirements of the
application. Also, the STA thread should never perform unbounded non-pumping
operations, such as calling Console.ReadLine. Instead, the STA thread must
have a MTA thread perform the operation and then wait for the operation to
finish.
REFERENCES
Non-UI thread doesn't pump because they don't have message queue. That's
why they are called non-UI.
Further more non-UI STA threads cannot host (create) COM objects simply
because STA apartment marshal's via windows messages thus, the thread has
to have message queue (UI thread)

*** Not exactly, OLE checks if the thread has a window handle associated
when entering an STA, if not OLE creates a hidden window and a message
queue. But, you have to pump messages of course. Remember: One of the rules
of COM mandates re-entrency for STA hosted objects.
Exactly. That's exactly what happens. That's why if creating COM objects
in STA thread and the object has finalizer that calls Release, don't call
WaitForPandingFinalizers

Not exactly threre is a timeout.
Bad wording, it wait's a certain amount of time (that's changed in CLR v2).
Well. .NET has enough sync primitives (each of which I believe are based
on OS primitives at the moment)

Yes, but the OS primitives are wrapped by the CLR's synch. primitives. The
CLR is free to do anything he likes, you would be supprised to see what he's
doing before calling into the OS :-)
The bottom line: When the thread is blocked that's it it is blocked,
period. There is no semiblocked threads.
While GC.WaitFor.... and COM object is not easily to verify (fortunately
there is KB article for that) all other sync methods can be tested. Just
run some tests and you'll see there is no pumping.

Just run the native debugger, and see there is pumping :-)
 
Back
Top