473,396 Members | 1,971 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Help me with threads.

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();
}
}
}


*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
Nov 16 '05 #1
22 4020
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.

"Jeff Louie" <je********@yahoo.com> a écrit dans le message de news:
%2******************@TK2MSFTNGP10.phx.gbl...
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();
}
}
}


*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!

Nov 16 '05 #2
Jeff Louie wrote:
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).

Nov 16 '05 #3
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

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
Nov 16 '05 #4
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

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
Nov 16 '05 #5
Jeff Louie wrote:
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.)
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().
2.Why not merge method_cin(), method_cerr(), and method_cout() into

one function?<
I believe these functions can deadlock.

If so, .net docs should have written about this.

Nov 16 '05 #6
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

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
Nov 16 '05 #7
I've got the opposite problem. I use threads a lot but I know doodly about
redirection. I'll look into it.
Nov 16 '05 #8

"Jeff Louie" <je********@yahoo.com> a écrit dans le message de news:
%2******************@TK2MSFTNGP10.phx.gbl...
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.

Regards,
Jeff

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!

Nov 16 '05 #9

"Jeff Louie" <je********@yahoo.com> a écrit dans le message de news:
ON***************@TK2MSFTNGP09.phx.gbl...
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.

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.<
*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!

Nov 16 '05 #10
Bruno Jouhier [MVP] wrote:
"Jeff Louie" <je********@yahoo.com> a écrit dans le message de news: ON***************@TK2MSFTNGP09.phx.gbl...
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.


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.

Nov 16 '05 #11
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.<

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
Nov 16 '05 #12
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

"Jeff Louie" <an*******@devdex.com> a écrit dans le message de news:
uQ**************@TK2MSFTNGP12.phx.gbl...
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.<

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!

Nov 16 '05 #13
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.
"Bruno Jouhier [MVP]" <bj******@club-internet.fr> wrote in message
news:Od**************@TK2MSFTNGP12.phx.gbl...
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

"Jeff Louie" <an*******@devdex.com> a écrit dans le message de news:
uQ**************@TK2MSFTNGP12.phx.gbl...
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.<

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!


Nov 16 '05 #14

"Jason Black [MSFT]" <ja*****@microsoft.com> a écrit dans le message de
news: 41********@news.microsoft.com...
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 [MVP]" <bj******@club-internet.fr> wrote in message
news:Od**************@TK2MSFTNGP12.phx.gbl...
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

"Jeff Louie" <an*******@devdex.com> a écrit dans le message de news:
uQ**************@TK2MSFTNGP12.phx.gbl...
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.<

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!



Nov 16 '05 #15
Bruno Jouhier [MVP] <bj******@club-internet.fr> wrote:
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/tutor...c/threads.html
for more information.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #16

"Jon Skeet [C# MVP]" <sk***@pobox.com> a écrit dans le message de news:
MP************************@msnews.microsoft.com...
Bruno Jouhier [MVP] <bj******@club-internet.fr> wrote:
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.


Then, they have changed things since I used these toolkits. I worked with
the first releases (AWT in 96-98, just a little bit of Swing, no SWT but I
assumed it was the same) and there was no such thing at the time (but lots
of ugly deadlocks in AWT). They probably had to go this way to be able to
take advantage of the fast MFC controls when running on Windows, and to get
rid of their awful deadlocks.

Bruno

See http://java.sun.com/docs/books/tutor...c/threads.html
for more information.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 16 '05 #17
This is not correct, Windows.Forms is built on top of Windows and has
nothing to do with COM apartments , unless your controls are activeX
controls, in which case they are apartment threaded so must be accessed only
from that thread that created the control.
The fact that you should only access UI elements from the thread that
created them is because "Window Handles" (HWND) have thread affinity.
Note that this also applies to other toolkits, everything that runs on
windows has to respect that simple rule "use your 'Window handles' only from
the thread that created them".

Willy.

"Bruno Jouhier [MVP]" <bj******@club-internet.fr> wrote in message
news:Od**************@TK2MSFTNGP12.phx.gbl...
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

"Jeff Louie" <an*******@devdex.com> a écrit dans le message de news:
uQ**************@TK2MSFTNGP12.phx.gbl...
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.<

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!


Nov 16 '05 #18
Bruno Jouhier [MVP] <bj******@club-internet.fr> wrote:
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.


Then, they have changed things since I used these toolkits. I worked with
the first releases (AWT in 96-98, just a little bit of Swing, no SWT but I
assumed it was the same) and there was no such thing at the time (but lots
of ugly deadlocks in AWT). They probably had to go this way to be able to
take advantage of the fast MFC controls when running on Windows, and to get
rid of their awful deadlocks.


Swing has always been the same, as far as I'm aware. I'm not sure about
AWT, but I doubt that they'd make such a breaking change late on. It
may well not have been well documented, of course...

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #19

"Jon Skeet [C# MVP]" <sk***@pobox.com> a écrit dans le message de news:
MP************************@msnews.microsoft.com...
Bruno Jouhier [MVP] <bj******@club-internet.fr> wrote:
> 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.
Then, they have changed things since I used these toolkits. I worked with
the first releases (AWT in 96-98, just a little bit of Swing, no SWT but
I
assumed it was the same) and there was no such thing at the time (but
lots
of ugly deadlocks in AWT). They probably had to go this way to be able to
take advantage of the fast MFC controls when running on Windows, and to
get
rid of their awful deadlocks.


Swing has always been the same, as far as I'm aware. I'm not sure about
AWT, but I doubt that they'd make such a breaking change late on. It
may well not have been well documented, of course...


I looked a bit more into this:

Swing and SWT are not free-threaded (except for some very specific calls in
the Swing toolkit). So, you have to go through the invoke calls if you are
calling from another thread. And I was completely wrong on those (I
extrapolated too quickly from my early AWT experience).

AWT sounds more complex: internally, there is a single thread that accesses
the message queue and the drawing methods, but externally, you are allowed
to call the AWT methods from several threads. This leads to extra complexity
and inefficiencies in the toolkit, which is why a different approach was
taken by Swing and SWT. So, from what I've found on Google (which is not
always very clear), it seems that AWT is still free threaded from the
outside, even if it is single threaded inside.

Actually, it would not be too difficult to turn the WinForms toolkit into a
free threaded toolkit "from the outside", you would just need to rewrite
every public API entry point as:

foo()
{
if (InvokeRequired)
BeginInvoke(new FooDelegate(internalFoo));
else
internalFoo();
}

The toolkit would then be free threaded "from the outside" but it would be
slower.

Bruno.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 16 '05 #20
Bruno... Sorry about the late reply, but I think my brain just was
overloaded
with too much new stuff :). I really appreciate your looking at my code
and
finding such a fundamental error. I have updated the code at my site,
but still
working things out in my head.

Regards,
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).

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
Nov 16 '05 #21
Jason... Thanks for the great post. I was able to just follow your
example and
redesign my little class using events and delegates and I updated the
code on
my website. Honestly, I have not yet gotten my head completely around
how
delegates and events work especially concerning when the auto generated
class that "encapsulates a type safe function is called," but I expect
it will
come to me eventually.

Regards,
Jeff
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.<

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
Nov 16 '05 #22
I'll be the first to admit that it took me a while to get my head around it
too. Mostly, I think, the difficulty is not with the concepts themselves
but with the layers of C# semantic and syntactic glue that you need to lay
down in order to make your application compile and be correct. In
particular, the need to go to such extensive trouble just to define an event
that passes data back to its handlers seems unduly burdensome. This is
something that I am hopeful a future version of C# and Visual Studio will
make easier (for example, if the compiler could infer the delegate
declaration for you, and if the IDE could write the EventArgs class
declaration for you, that would be enormously helpful). Of course, not
being on the teams that work on those things myself, I cannot say one way or
the other whether such features are on anybody's to-do list...

"Jeff Louie" <je********@yahoo.com> wrote in message
news:%2****************@TK2MSFTNGP15.phx.gbl...
Jason... Thanks for the great post. I was able to just follow your
example and
redesign my little class using events and delegates and I updated the
code on
my website. Honestly, I have not yet gotten my head completely around
how
delegates and events work especially concerning when the auto generated
class that "encapsulates a type safe function is called," but I expect
it will
come to me eventually.

Regards,
Jeff
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.<

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!

Nov 16 '05 #23

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

Similar topics

1
by: Huzefa | last post by:
I am working on a amll project in Java that includes many classes. Each of the classes has a Logger object. I have associated a FileHandler with each of these Logger objects. The file is the same...
0
by: pptran | last post by:
Hi, I am pretty new to building and installing Perl. Can someone help explain the severity of the following Perl 5.8.4 build error message? ==================================================...
4
by: Madhu Gopinathan | last post by:
Hi All, I am faced with a horrible hang problem. I have a COM exe server that executes some tasks. The task execution manager is a thread that manages the pool of threads, which is 4 per processor....
5
by: MS Newsgroups | last post by:
Hi, I have an application that runs a timer and executes a method in a class as a new thread every 60 seconds, the thread takes 65 seconds to execute so there is a 5 second overlap when 2...
6
by: James Radke | last post by:
Hello, I have a multithreaded windows NT service application (vb.net 2003) that I am working on (my first one), which reads a message queue and creates multiple threads to perform the processing...
3
by: Chris Calzaretta | last post by:
Hello Working with system.threading.thread Ok I have an windows user control. It has 3 thread on it thread 1 uploaded files types a thread 2 upload files types b thread 3 upload files types c...
1
by: treelife | last post by:
I'm getting and internal server error when | run the following mod_python script. I am actually trying to run Django. Script: from mod_python import apache def handler(req):...
15
by: Jay | last post by:
I have a multi threaded VB.NET application (4 threads) that I use to send text messages to many, many employees via system.timer at a 5 second interval. Basically, I look in a SQL table (queue) to...
5
by: bean330 | last post by:
Hey, I'm somewhat new to C# and I need a little help, please! I'm selecting a bunch of records, setting properties on a COM executable and then calling a method on that executable to run. I...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
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
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,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
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...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

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.