Help me with threads.

J

Jeff Louie

Well I wonder if my old brain can handle threading. Dose this code look
reasonable.

Regards,
Jeff

using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace TestThreadedConsole
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
StreamReader my_cout;
StreamReader my_cerr;
StreamWriter my_cin;
Process myProcess = new Process();
Thread thread_cout;
Thread thread_cin;
Thread thread_cerr;
Thread thread_loop;
public void TryToExit()
{
while (!myProcess.HasExited)
{
Thread.Sleep(100);
}
if (thread_cout.IsAlive){thread_cout.Abort();}
if (thread_cin.IsAlive) {thread_cin.Abort();}
if (thread_cerr.IsAlive) {thread_cerr.Abort();}
myProcess.Close();
}
public void method_cout()
{
while(!myProcess.HasExited)
{
Console.WriteLine(my_cout.ReadLine());
}
}
public void method_cin()
{
while(!myProcess.HasExited)
{
my_cin.WriteLine(Console.ReadLine());
}
}
public void method_cerr()
{
while(!myProcess.HasExited)
{
Console.WriteLine(my_cerr.ReadLine());
}
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//// TODO: Add code to start application here//
///
new Class1();
}
public Class1()
{
ProcessStartInfo myProcessStartInfo =
new ProcessStartInfo("ConsoleServer.exe" );
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
myProcessStartInfo.RedirectStandardError= true;
myProcessStartInfo.RedirectStandardInput= true;
//myProcessStartInfo.Arguments= "";
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
my_cout= myProcess.StandardOutput;
my_cerr= myProcess.StandardError;
my_cin= myProcess.StandardInput;
thread_cout= new Thread(new ThreadStart(this.method_cout));
thread_cout.IsBackground= true;
thread_cin= new Thread(new ThreadStart(this.method_cin));
thread_cin.IsBackground= true;
thread_cerr= new Thread(new ThreadStart(this.method_cerr));
thread_cerr.IsBackground= true;
thread_loop= new Thread(new ThreadStart(this.TryToExit));
thread_cout.Start();
thread_cin.Start();
thread_cerr.Start();
thread_loop.Start();
}
}
}
 
B

Bruno Jouhier [MVP]

You are probably asking too much from the people who help on this newsgroup.

If you post tens of lines of code and just ask "does this look reasonable",
you are not very likely to get answers. You must give more info:
* what are you trying to achieve?
* how did you set it up (the general idea)
* what is not working as expected.
Then, you may get some answers.

Bruno.
 
A

Aquila Deus

Jeff said:
Well I wonder if my old brain can handle threading. Dose this code look
reasonable.

It seems reasonable, but:

1.Why put the main code in Class1's constructor??
2.Why not merge method_cin(), method_cerr(), and method_cout() into one
function?
3.I remember there is some method to set the current in, out, and err,
which means that you may redirect in/out from the child process to the
current in/out directly (if you don't want to make any modification).
 
J

Jeff Louie

Aquila... Inline.
1.Why put the main code in Class1's constructor??<
Actually, I have the opposite question. Why do samples put the code in
main since there is no guarantee that the code in main will ever
execute? If Class1 is a multithreaded Model class called from a GUI,
main in Class1 will not be called. (I pretty much just use main for unit
testing.)
2.Why not merge method_cin(), method_cerr(), and method_cout() into one
function?<
I believe these functions can deadlock.

Regards,
Jeff
 
J

Jeff Louie

Bruno... The code works fine. According to MS redirecting cerr and cin
using the Process class can cause deadlock. The recommended solution is
to use separate threads for redirecting cerr and cin. I have very little
experience with multi-threaded programming and was wondering if there
were any blatant errors in my approach to creating separate threads for
cin, cerr and cout. To test this code, I just wrote a C++ app that reads
cin and outputs to cerr and cout in a loop. The only problem that I have
is that cerr is going into a black hole, even when I call my C++ app
from the command line.

Regards,
Jeff
 
A

Aquila Deus

Jeff said:
Aquila... Inline.

Actually, I have the opposite question. Why do samples put the code in
main since there is no guarantee that the code in main will ever
execute? If Class1 is a multithreaded Model class called from a GUI,
main in Class1 will not be called. (I pretty much just use main for unit
testing.)

ah but main() is the entry point of the assembly. After all you have to
create the class in main() or some methods called by main().
one
function?<
I believe these functions can deadlock.
If so, .net docs should have written about this.
 
J

Jeff Louie

Aqula...
ah but main() is the entry point of the assembly. After all you have to
create the class in main() or some methods called by main().<


True, but every class can have a main, but only the entry point main is
called. So IMHO putting the threading logic in main is silly. The main
in MyGUI class should not need to know the threading logic of MyModel
class. IMHO,MyModel should encapsulate its threading logic inside the
class, not in its main method.
If so, .net docs should have written about this.<

Actually the process class docs do document this and it is the documents
that suggest using separate threads for cerr and cout.

Regards,
Jeff
 
P

Peter Wone

I've got the opposite problem. I use threads a lot but I know doodly about
redirection. I'll look into it.
 
B

Bruno Jouhier [MVP]

Jeff Louie said:
Bruno... The code works fine. According to MS redirecting cerr and cin
using the Process class can cause deadlock. The recommended solution is
to use separate threads for redirecting cerr and cin. I have very little
experience with multi-threaded programming and was wondering if there
were any blatant errors in my approach to creating separate threads for
cin, cerr and cout. To test this code, I just wrote a C++ app that reads
cin and outputs to cerr and cout in a loop. The only problem that I have
is that cerr is going into a black hole, even when I call my C++ app
from the command line.

Jeff; This info was useful to understand your problem.

I don't know much about redirecting standard outputs and inputs but what you
are trying to do seems logical.

I don't see anything wrong in what you wrote, and the fact that you don't
get anything on cerr is a bit mysterious to me (does the subprocess actually
write to cerr? does it flush?).

In such a simple program, you won't have any special issue with
multithreading, but if you start to make it more sophisticated, you have to
be careful about a number of things. For example, in this program you have
two streams that write to the console. This works ok because
Console.WriteLine is thread-safe. But if instead you were appending the
lines to an ArrayList and if you were using the same ArrayList for the two
streams, you would need to "synchronize" the operations on the ArrayList.

This is the kind of thing that you have to worry about when you start to
program with several threads. One of the basic questions that you need to
ask yourself over and over is:
"Is this object accessed only by the current thread, or is it shared by
several threads?"
If it is shared (the Console object is in your example), you then need to
ask yourself:
"Is is thread safe? or is it up to me to synchronize?" (the Console is
thread safe, no worry).

One of the difficulties is that most bugs are race condition bugs, they are
difficult to reproduce and you can waste a lot of time tracking them down if
you don't have a good understanding of multi-threading and synchronization
issues. So, if you are going to write multi-threaded code with
synchronization and object sharing issues, I would recommend that you take
the time to read a good book about it (Doug Lea for example, it's Java but
the concepts are the same) and that you do a few exercises with small
classical examples (producer and consumer for example) to be sure that you
understand the basic concepts (monitors, wait() and pulse(), deadlocks,
etc.). Afterwards, it is just a question of being rigorous, and just a bit
more careful than in single threaded programs.

Hope this helps.

Bruno.
 
J

Jeff Louie

Bruno... Thanks for the reply. I had not even thought about
Console.WriteLine
being thread safe! Indeed I think that I have a fear of multithreaded
programming and concurrent programming. When Java was young, I wrote a
socket server and client program that used threads to communicate and
was
criticized for posting experimental code! Strange to see threads now
recommended for a similar scenario.

Regards,
Jeff
For example, in this program you have
two streams that write to the console. This works ok because
Console.WriteLine is thread-safe. But if instead you were appending the
lines to an ArrayList and if you were using the same ArrayList for the
two
streams, you would need to "synchronize" the operations on the
ArrayList.<
 
A

Aquila Deus

Jeff said:
Aqula... to
create the class in main() or some methods called by main().<


True, but every class can have a main, but only the entry point main is
called. So IMHO putting the threading logic in main is silly. The main
in MyGUI class should not need to know the threading logic of MyModel
class. IMHO,MyModel should encapsulate its threading logic inside the
class, not in its main method.

It depends. If the thread is only used inside the class, then it should
be in the class' code. But putting it inside constructor is weird...
Actually the process class docs do document this and it is the documents
that suggest using separate threads for cerr and cout.

But why?
 
B

Bruno Jouhier [MVP]

Jeff Louie said:
Bruno... Thanks for the reply. I had not even thought about
Console.WriteLine
being thread safe! Indeed I think that I have a fear of multithreaded
programming and concurrent programming. When Java was young, I wrote a
socket server and client program that used threads to communicate and
was
criticized for posting experimental code! Strange to see threads now
recommended for a similar scenario.

It is probably better to be a bit fearful about them than to be fearless and
get wild about them.

Threads are difficult but they are just the right tool in some situations,
especially on the server side. Using them to handle multiple I/O channels
(your example) is a very common pattern. On a server, you typically use a
thread pool to serve several connections concurrently. This is very
important because it allows you to use the CPU efficiently on thread that
have their data available while some other threads are blocked waiting for
I/O. Without threads, you would get very bad throuput because your server
would be constantly blocked on I/O conditions (or you would have to spawn
processes, which is more resource intensive, or use asynch I/O which may be
tricky too).

So, threads an not "experimental" any more, they are starting to be
"mainstream". But they are still tricky.

Bruno.
 
J

Jeff Louie

Aquila... It may be weird, but I don't see how else to encapsulate the
threading logic. I rewrote the class as a generic reusable class and
called it from a Windows Form Program. All of the threading logic is in
the class constructor of ThreadedProcess. Here is the button submit
click handler that demonstrates how the GUI class interacts with the
generic ThreadedProcess class.

private void buttonSubmit_Click(object sender, System.EventArgs e)
{
// get arguments
StringReader your_cin= new StringReader(textBoxInput.Text);
StringWriter your_cout= new StringWriter();
StringWriter your_cerr= new StringWriter();
int timeOut= 1000;
try
{
timeOut= Int32.Parse(textBoxTimeOut.Text);
}
catch{}
string pathToExe= textBoxPath.Text;

// call console app
process = new ThreadedProcess(pathToExe,
null,
1000,
your_cin,
your_cout,
your_cerr);

// display results
textBoxOut.Text= your_cout.ToString();
textBoxError.Text= your_cerr.ToString();
textBoxExitCode.Text= process.ExitCode.ToString();
}

Regards,
Jeff
If the thread is only used inside the class, then it should be in the
class' code. But putting it inside constructor is weird...<
 
A

Aquila Deus

Bruno said:
"Jeff Louie" <[email protected]> a écrit dans le message de news:

It is probably better to be a bit fearful about them than to be fearless and
get wild about them.

Threads are difficult but they are just the right tool in some situations,
especially on the server side. Using them to handle multiple I/O channels
(your example) is a very common pattern. On a server, you typically use a
thread pool to serve several connections concurrently. This is very
important because it allows you to use the CPU efficiently on thread that
have their data available while some other threads are blocked waiting for
I/O. Without threads, you would get very bad throuput because your server
would be constantly blocked on I/O conditions (or you would have to spawn
processes, which is more resource intensive, or use asynch I/O which may be
tricky too).

So, threads an not "experimental" any more, they are starting to be
"mainstream". But they are still tricky.

Or maybe .NET could provide a higher-level interface for thread? Erlang
does this very well and you can use threads like objects without
worrying about resource problem. I haven't seen similiar thing for any
C-like language though.
 
J

Jeff Louie

Bruno... Boy that was an understatement. I have spent a _lot_ of time
getting my ThreadedProcess class to work. I had to add a timer to let
the threads complete their task after the console application exited and
added a delegate to notify the caller when the the ThreadedProcess had
closed. I then had to use a thread in the GUI to launch the
ThreadedProcess. If you are up to looking at my code, I updated the page
at:

http://www.geocities.com/jeff_louie/call_console.htm

Regards,
Jeff
So, threads an not "experimental" any more, they are starting to be
"mainstream". But they are still tricky.<
 
B

Bruno Jouhier [MVP]

Jeff,

I looked quickly at your example, and I see a potential problem with your
"callback" method: this method is called from your thread (ThreadedProcess)
and it interacts with the GUI (it appends text to the textBoxControls). You
have put a monitor to protect it from multi-thread access.

This would work ok if WinForms used a "free threaded" model (like the Java
toolkits for example), but unfortunately, WinForms is built on top of COM
components and it uses an "apartment threaded" model. So, you are not
allowed to directly call methods on WinForms components if they have been
created by a different thread than yours (you are not allowed to append text
to your textBox controls because these controls belong to a different
thread). Instead, you have to use the Control.Invoke method everytime you
want to interact with these WinForms components from another thread.
Control.Invoke will package the call as a Windows message, it will post the
message to the message queue of the thread that created the component, and
it will wait for the message to be processed and then return the results to
your thread.

I see that you have used a timeout in Monitor.Enter. I suspect that this is
because you have been experiencing some deadlocks in the code that writes to
the textBox controls. These deadlocks are typical of cross-thread calls to
WinForm components. If you rewrite your callback method so that it goes
through Control.Invoke instead, you will see that you won't need any timeout
any more, and that you can get rid of the Monitor.Enter/Exit calls, because
Control.Invoke is thread-safe (nothing bad happens if two or more threads
call Control.Invoke at the same time).

Threading is difficult, but Microsoft makes it a bit harder because you have
to deal with the "appartment models" that get inherited from COM.

Hope this helps.

Bruno
 
J

Jason Black [MSFT]

While Bruno is entirely correct that you shouldn't be trying to update UI
controls from a worker thread, I disagree that dealing with this situation
is really all that hard. It's kind of hard the first time you do it, but
after that it's really not a big deal. That is, it's sort of a lot to get
your head around if you've never worked with delegates or BeginInvoke
before, but the concepts reduce down to a pretty small amount of actual code
that you need to write.

What you need to do is to define an event that your worker thread can throw
when it needs to send data back to the UI thread, create an event handler to
process that event, and in the event handler do a little bit of work to make
sure that you're in the correct thread before you update your UI controls.
To update a text box (or the .Text field of any control, really), for
example, you'll need to do something like this:

// First, declare a delegate called "StringEventHandler" to hold the
function
// prototype information which connects events with their handlers. The
// delegate is the mechanism by which the compiler enforces type-safety
// between events and their handlers.
public delegate void StringEventHandler(object worker, StringEventArgs e);

// Oh, look, we just referenced something called "StringEventArgs". That's
// a class we need to make, derived from EventArgs, to hold the actual
string
// data we want the worker thread to pass back to the UI thread:
public class StringEventArgs : EventArgs {
public string TheString; // surely you'll come up with a better name
than this.
public StringEventArgs(string S) { TheString = s; }
}

// Now we go ahead and declare an event called "OnStringEvent", which is of
// type "StringEventHandler". This guarantees that only functions which are
expecting
// a StringEventArgs object will be allowed to subscribe to the event.
public event StringEventHandler OnStringEvent;

// Your event handler is really just a function which wraps the "are we on
the right
// thread? If not, switch" logic around whatever UI updating you wanted to
do in
// the first place.
private void MyStringEventHandler(object worker, StringEventArgs e) {
if(myTextBox.InvokeRequired) {
this.BeginInvoke(new StringEventHandler(MyStringEventHandler),
new object[]{worker,e});
} else {
myTextBox.Text = e.TheString;
}
}

// Of course, somewhere you need to make sure that your event handler is
// actually subscribed to the event itself (this is a good thing to do in
your
// form's constructor, after the InitializeComponent() call.
OnStringEvent += new StringEventHandler(MyStringEventHandler);

// and finally, when it's time, the worker thread needs to raise the event
in
// order to trigger whatever event handlers have subscribed to it:
if(OnStringEvent != null) // don't do anything if nobody has subscribed.
OnStringEvent(this, new StringEventArgs(someString));

I remember when I was learning this stuff there were two parts that hurt my
brain the most. The first was understanding how the delegate related to the
event and the event handler. When my C/C++ addled brain figured out "oh,
delegates are how we make type-safe function pointers", then that part was
ok. It took me a while to figure that out, because none of the books I was
reading just came right out and said that, but that's really what they're
for. The "new StringEventHandler(MyStringEventHandler)" is just the C#
object-oriented way to express the "function pointer" itself.

The second hard thing was understanding what was going on with BeginInvoke.
The job of BeginInvoke is to do some sort of internal magic in order to be
executing in the same thread as "this" (your form's thread, which is the
thread that created all your UI controls, and is therefore the right thread
on which to update those controls), and then to call whatever function you
like for you, over in that thread. To do that last part, BeginInvoke needs
a pointer to our event handler, plus an object array containing the
arguments that will be passed to our event handler. That the event handler
uses BeginInvoke to call itself is largely a matter of convention. There
are other ways this could work (the worker thread could use BeginInvoke to
switch threads before raising the event, for instance, or the UI thread
could use BeginInvoke to call a helper function which actually updates the
control), but this is the pattern that WinForms developers have come to more
or less standardize on, as it seems to involve the least mess and it puts
the responsibility for being on the right thread in the right place: with
the control that insists on that in the first place. Sort of like telling
the form "well, if you don't want your controls to be updated from some
other thread, then you do the thread switching. Don't bother me with that
crap."

To sum up, then, the runtime sequence of actions involved in getting your UI
control updated is:

1. The worker thread decides it needs to send a string back to the UI, so it
constructs a StringEventArgs object to hold the string, and then raises the
event.
2. The event handler gets invoked, still running in the worker thread.
3. The event handler checks, by means of this.InvokeRequired, to see whether
it's in the worker thread or the UI thread.
4. It will discover that it's still in the worker thread, and will call
BeginInvoke with the right information so that BeginInvoke will call the
event handler again after switching threads.
5. The event handler gets invoked a second time, with all the same arguments
as before, only now it's running in the UI thread.
6. The event handler checks, by means of this.InvokeRequired, to see whether
it's in the worker thread or the UI thread.
7. It will discover that it's in the UI thread, so it will get the string
out of the StringEventArgs object and put it in the text box's .Text field.

One other note: in a simple application, it's fine to put all of that code
inside the form itself. You'll have no problems with namespaces, etc. If
your application is complex enough that you've encapsulated the worker
thread in its own class (and there are plenty of good reasons to do this
which I won't go into), then you should put the delegate declaration, the
EventArgs-derived class, and the event into the worker thread's class, and
put the event handler in your Form class. Just make sure that the event and
the EventArgs objects are public so that your Form class can see them.
 
B

Bruno Jouhier [MVP]

Jason Black said:
While Bruno is entirely correct that you shouldn't be trying to update UI
controls from a worker thread, I disagree that dealing with this situation
is really all that hard. It's kind of hard the first time you do it, but
after that it's really not a big deal. That is, it's sort of a lot to get
your head around if you've never worked with delegates or BeginInvoke
before, but the concepts reduce down to a pretty small amount of actual
code that you need to write.

The difficult thing here is not really writing the code. Once you 've got a
good example, it is actually quite simple (and your post explains it very
well).

The difficult part is to find your way through the jungle if this is your
first step into multi-thread programming. And I have the impression that
Jeff tried to figure out the solution by himself rather than by cloning an
example. So, he read about multi-threading, monitors, etc. and he came up
with a solution that would have worked with any free-threaded toolkit (AWT,
Swing, SWT) but that does not work with WinForms because of the "appartment
threading" issue (and he had to introduce a timeout hack to get it working
most of the time). In short, Jeff walked through the jungle but did not find
the right path.

Actually, once you know about "appartement threading" and about
Control.Invoke/BeginInvoke, the whole thing becomes simpler because these
calls are thread-safe, and the pure UI code is executed by a single thread.
This is relatively easy to understand for someone who has been doing
multi-threading for a while, but for someone who makes his first steps, this
whole thing (learning about threads, monitors, and then discovering
apartment threading and Control.Invoke, and trying to figure out if monitors
still make sense in this context, etc.) sounds rather overwhelming to me.

Maybe some kind of "expert system" would help here:

Question: what objects does your thread interact with?
a) only objects created by the thread itself
b) objects created by the thread itself and UI objects created by the UI
thread
c) objects created by the thread itself and non UI objects created by
other threads
d) a mixture of the above.

Answer:
a) You are on the safe side (but check twice that you are really in this
case, make sure you did not forget a static variable or a an object that is
shared by the two threads, or a static method that is called by both threads
and accesses a static variable without any synchronization, etc.).

b) Learn about Control.Invoke and Control.BeginInvoke. Don't worry about
monitors, unless you are in case d (check this twice, as in case a)

c) Learn about monitors, the C# lock keyword, deadlocks, etc.

d) Make sure you understand the whole thing.

Also, beware of COM components. They usually use apartment threading models.
So, replace "UI objects" by "apartment threaded COM components" in all the
above.

This is why I said that Microsoft makes it harder. Other multi-threaded
systems (like Java) don't mix free threading and apartment threading, and
you only need to deal with cases a) and c). And it is a bit easier to find
one's way through the jungle.

Bruno.
What you need to do is to define an event that your worker thread can
throw when it needs to send data back to the UI thread, create an event
handler to process that event, and in the event handler do a little bit of
work to make sure that you're in the correct thread before you update your
UI controls. To update a text box (or the .Text field of any control,
really), for example, you'll need to do something like this:

// First, declare a delegate called "StringEventHandler" to hold the
function
// prototype information which connects events with their handlers. The
// delegate is the mechanism by which the compiler enforces type-safety
// between events and their handlers.
public delegate void StringEventHandler(object worker, StringEventArgs e);

// Oh, look, we just referenced something called "StringEventArgs".
That's
// a class we need to make, derived from EventArgs, to hold the actual
string
// data we want the worker thread to pass back to the UI thread:
public class StringEventArgs : EventArgs {
public string TheString; // surely you'll come up with a better name
than this.
public StringEventArgs(string S) { TheString = s; }
}

// Now we go ahead and declare an event called "OnStringEvent", which is
of
// type "StringEventHandler". This guarantees that only functions which
are expecting
// a StringEventArgs object will be allowed to subscribe to the event.
public event StringEventHandler OnStringEvent;

// Your event handler is really just a function which wraps the "are we on
the right
// thread? If not, switch" logic around whatever UI updating you wanted
to do in
// the first place.
private void MyStringEventHandler(object worker, StringEventArgs e) {
if(myTextBox.InvokeRequired) {
this.BeginInvoke(new StringEventHandler(MyStringEventHandler),
new object[]{worker,e});
} else {
myTextBox.Text = e.TheString;
}
}

// Of course, somewhere you need to make sure that your event handler is
// actually subscribed to the event itself (this is a good thing to do in
your
// form's constructor, after the InitializeComponent() call.
OnStringEvent += new StringEventHandler(MyStringEventHandler);

// and finally, when it's time, the worker thread needs to raise the event
in
// order to trigger whatever event handlers have subscribed to it:
if(OnStringEvent != null) // don't do anything if nobody has subscribed.
OnStringEvent(this, new StringEventArgs(someString));

I remember when I was learning this stuff there were two parts that hurt
my brain the most. The first was understanding how the delegate related
to the event and the event handler. When my C/C++ addled brain figured
out "oh, delegates are how we make type-safe function pointers", then that
part was ok. It took me a while to figure that out, because none of the
books I was reading just came right out and said that, but that's really
what they're for. The "new StringEventHandler(MyStringEventHandler)" is
just the C# object-oriented way to express the "function pointer" itself.

The second hard thing was understanding what was going on with
BeginInvoke. The job of BeginInvoke is to do some sort of internal magic
in order to be executing in the same thread as "this" (your form's thread,
which is the thread that created all your UI controls, and is therefore
the right thread on which to update those controls), and then to call
whatever function you like for you, over in that thread. To do that last
part, BeginInvoke needs a pointer to our event handler, plus an object
array containing the arguments that will be passed to our event handler.
That the event handler uses BeginInvoke to call itself is largely a matter
of convention. There are other ways this could work (the worker thread
could use BeginInvoke to switch threads before raising the event, for
instance, or the UI thread could use BeginInvoke to call a helper function
which actually updates the control), but this is the pattern that WinForms
developers have come to more or less standardize on, as it seems to
involve the least mess and it puts the responsibility for being on the
right thread in the right place: with the control that insists on that in
the first place. Sort of like telling the form "well, if you don't want
your controls to be updated from some other thread, then you do the thread
switching. Don't bother me with that crap."

To sum up, then, the runtime sequence of actions involved in getting your
UI control updated is:

1. The worker thread decides it needs to send a string back to the UI, so
it constructs a StringEventArgs object to hold the string, and then raises
the event.
2. The event handler gets invoked, still running in the worker thread.
3. The event handler checks, by means of this.InvokeRequired, to see
whether it's in the worker thread or the UI thread.
4. It will discover that it's still in the worker thread, and will call
BeginInvoke with the right information so that BeginInvoke will call the
event handler again after switching threads.
5. The event handler gets invoked a second time, with all the same
arguments as before, only now it's running in the UI thread.
6. The event handler checks, by means of this.InvokeRequired, to see
whether it's in the worker thread or the UI thread.
7. It will discover that it's in the UI thread, so it will get the string
out of the StringEventArgs object and put it in the text box's .Text
field.

One other note: in a simple application, it's fine to put all of that code
inside the form itself. You'll have no problems with namespaces, etc. If
your application is complex enough that you've encapsulated the worker
thread in its own class (and there are plenty of good reasons to do this
which I won't go into), then you should put the delegate declaration, the
EventArgs-derived class, and the event into the worker thread's class, and
put the event handler in your Form class. Just make sure that the event
and the EventArgs objects are public so that your Form class can see them.


Bruno Jouhier said:
Jeff,

I looked quickly at your example, and I see a potential problem with your
"callback" method: this method is called from your thread
(ThreadedProcess) and it interacts with the GUI (it appends text to the
textBoxControls). You have put a monitor to protect it from multi-thread
access.

This would work ok if WinForms used a "free threaded" model (like the
Java toolkits for example), but unfortunately, WinForms is built on top
of COM components and it uses an "apartment threaded" model. So, you are
not allowed to directly call methods on WinForms components if they have
been created by a different thread than yours (you are not allowed to
append text to your textBox controls because these controls belong to a
different thread). Instead, you have to use the Control.Invoke method
everytime you want to interact with these WinForms components from
another thread. Control.Invoke will package the call as a Windows
message, it will post the message to the message queue of the thread that
created the component, and it will wait for the message to be processed
and then return the results to your thread.

I see that you have used a timeout in Monitor.Enter. I suspect that this
is because you have been experiencing some deadlocks in the code that
writes to the textBox controls. These deadlocks are typical of
cross-thread calls to WinForm components. If you rewrite your callback
method so that it goes through Control.Invoke instead, you will see that
you won't need any timeout any more, and that you can get rid of the
Monitor.Enter/Exit calls, because Control.Invoke is thread-safe (nothing
bad happens if two or more threads call Control.Invoke at the same time).

Threading is difficult, but Microsoft makes it a bit harder because you
have to deal with the "appartment models" that get inherited from COM.

Hope this helps.

Bruno
 
J

Jon Skeet [C# MVP]

Bruno Jouhier said:
The difficult part is to find your way through the jungle if this is your
first step into multi-thread programming. And I have the impression that
Jeff tried to figure out the solution by himself rather than by cloning an
example. So, he read about multi-threading, monitors, etc. and he came up
with a solution that would have worked with any free-threaded toolkit (AWT,
Swing, SWT) but that does not work with WinForms because of the "appartment
threading" issue (and he had to introduce a timeout hack to get it working
most of the time). In short, Jeff walked through the jungle but did not find
the right path.

Just to correct something - Swing and AWT (and possibly SWT as well,
not sure) also require you to only access UI objects in the UI thread.
That's what SwingUtilities.invokeLater/invokeAndWait are for.

See http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
for more information.
 

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