Threads and events (again)

E

Elisa

Hi,

I already asked something similar previously, but I still haven't
completely grasped the concept of threads and events.

I'm trying to design an app using the Observer pattern and the Command
pattern, e.g. my GUI adds commands to a queue, this queue process these
commands in a seperate thread, and notifies any listeners (read: the
GUI) of state changes, progress, etc.

Thus, a rather classical approach, but...

The interaction between threads and events confuses me, and the VB .NET
documentation sadly doesn't say a word about how events behave with
multiple threads :-(

I now that if I want to change the GUI directly from outside the GUI's
main thread, I need to use Control.Invoke().

But does that also apply if I fire events (using RaiseEvent)? I.e.
because the notifications (read: events) are fired from the queue's
processing thread, does this mean that the code inside my listeners
(read: event handlers) must use Control.Invoke() to update the GUI?


Regards,

Elisa
 
J

Jon Skeet [C# MVP]

Elisa said:
I already asked something similar previously, but I still haven't
completely grasped the concept of threads and events.

I'm trying to design an app using the Observer pattern and the Command
pattern, e.g. my GUI adds commands to a queue, this queue process these
commands in a seperate thread, and notifies any listeners (read: the
GUI) of state changes, progress, etc.

Thus, a rather classical approach, but...

The interaction between threads and events confuses me, and the VB .NET
documentation sadly doesn't say a word about how events behave with
multiple threads :-(

I now that if I want to change the GUI directly from outside the GUI's
main thread, I need to use Control.Invoke().

But does that also apply if I fire events (using RaiseEvent)? I.e.
because the notifications (read: events) are fired from the queue's
processing thread, does this mean that the code inside my listeners
(read: event handlers) must use Control.Invoke() to update the GUI?

Assuming you're only making changes to the GUI within the GUI thread,
the GUI events will only be fired within the GUI thread too.

Of course, other events may be fired from other threads.
 
E

Elisa

Hi Jon,
Assuming you're only making changes to the GUI within the GUI thread,
the GUI events will only be fired within the GUI thread too.

Thanks, but that's not actually the question ;-)

Assume I have a form with an event handler OnActionCompleted() that
handles the ActionCompleted event. The event handler is added using
AddHandler inside the form's constructor. Now, from another thread, I
fire the ActionCompleted event using RaiseEvent. I'd like the event
handler to update a child control of the form (e.g. Me.Label1.Text =
"Done!"). Can I put that statement as-is in the event handler, or do I
need to call it indirectly using Control.Invoke()?


Regards,

Elisa
 
J

Jon Skeet [C# MVP]

Elisa said:
Thanks, but that's not actually the question ;-)

Assume I have a form with an event handler OnActionCompleted() that
handles the ActionCompleted event. The event handler is added using
AddHandler inside the form's constructor. Now, from another thread, I
fire the ActionCompleted event using RaiseEvent. I'd like the event
handler to update a child control of the form (e.g. Me.Label1.Text =
"Done!"). Can I put that statement as-is in the event handler, or do I
need to call it indirectly using Control.Invoke()?

Well, the usual way (IIRC) would be for OnActionCompleted itself not to
be the handler, but to be the thing which raises the event - other
methods would be the handlers themselves.

Where you add the handler is irrelevant - whichever thread ends up
firing the event is the thread which will call the handlers for the
event. You could decide to isolate a single point where the event is
actally fired, and make *that* do Control.Invoke if necessary.
Alternatively, each of the handlers could do Control.Invoke (if
necessary) if they're modifying the UI.
 
E

Elisa

Hi Jon,
Well, the usual way (IIRC) would be for OnActionCompleted itself not to
be the handler, but to be the thing which raises the event - other
methods would be the handlers themselves.

Admittedly, the names I choose are about as confusing as the naming
conventions suggested by Microsoft ;-)

Following Microsoft's nomenclature, the paragraph should read:

"Assume I have a form with an event handler
ActionCompletedEventHandler() that handles the ActionCompletedEvent
event. The event handler is added using AddHandler inside the form's
constructor. Now, inside another thread I have a method
OnActionCompleted, where I fire the ActionCompletedEvent event using
RaiseEvent. I'd like the event handler to update a child control of the
form (e.g. Me.Label1.Text = "Done!"). Can I put that statement as-is in
the event handler, or do I need to call it indirectly using
Control.Invoke()?"
Where you add the handler is irrelevant - whichever thread ends up
firing the event is the thread which will call the handlers for the
event.

Thanks, that's the answer I was looking for (sadly, not the answer I was
hoping for) ;-)


Regards,

Elisa
 
C

Chris Tacke, eMVP

I went through and re-did the events in the OpennETCF.IO.Serial.Port class
based on this exact same problem recently, so if you're after an example of
one way to marshal the events to the primary thread it would do.
 
E

Elisa

Hi Chris,
I went through and re-did the events in the OpennETCF.IO.Serial.Port class
based on this exact same problem recently, so if you're after an example of
one way to marshal the events to the primary thread it would do.

I looked at the code, but, if event handler code always runs in the same
thread that fired the event (dixit Jon), then I don't see how it would
accomplish marshalling events from the CommEventThread to the primary
thread.

E.g. from inside your CommEventThread you fire an event
m_DataReceived(). This will invoke the event handler
Port_m_DataReceived, whose code will still run inside the
CommEventThread. Inside the event handler you invoke another set of
event handlers, but surely, these TOO will run in the CommEventThread
context?!

I.e. what part of the code exactly will make the e() call run on the
primary thread?


Regards,

Elisa
 
R

Ryan Chapman [MSFT]

Hi Elisa,

Basically it's not a bad idea to use Invoke or BeginInvoke any time you're
updating a GUI and you're not sure of the context in which an event might
be called. The Invoke method doesn't incur a severe penalty, so it
shouldn't be much of a burden. (In desktop-land, you can use
"InvokeRequired" to determine whether or not you need to Invoke.)

Hope this helps,

Ryan Chapman
Software Development Engineer
.NET Compact Framework

This posting is provided "AS IS" with no warranties, and confers no rights.
 
D

Daniel Moth

Hi

Interesting... Do you mean that the serial class throws events on the GUI
thread by default?

I've always thought it is a mistake for a low level server component (e.g. a
SerialPort) to raise events on the GUI thread. Most users will want to
process the data (a stream of) on a background thread and occasionally
update the GUI. At that moment (or whenever), using Control.Invoke is easy
client-side... MS must agree with me since that is the way the socket and
serial classes work... At the very least there should be an option not to
use a Control internally in the class (much like System.Timers.Timer uses
the SynchronizingObject property by implementing the ISynchronizeInvoke)...

Note that I have no interest which way the implementation of the specific
serial class goes but I was just intrigued with the design decision at a
general level...

Cheers
Daniel
 
C

Chris Tacke, eMVP

It does now. Originally it threw them in the context of the receiving
thread, which caused some users problems if they wanted to update the UI
right from the event handler. Of course your argument for keeping the
handlers on a separate thread are well taken, and now I'm undecided which
way I should go. I think moving it *back* to the thread is probably
better - I was just trying to make life easier for beginners, but in doing
so I think I may have crippled functionality. Intersting thought - thanks
for bringing it up!
 
T

tcarvin

What I've done in my libraries in these cases is have the low-level
component raise its events on its own (worker) thread, but then provide
a wrapper class that can be used by GUI clients of the class. That
wrapper class takes as a constructor an instance of Control to perform
the Invoke calls to do the marshalling.

You can mirror the signitures in the wrapper, have them both implement
a common interface, give them a common base class, or have the wrapper
subclass the original component.

So say I have a class LowLevelWorker with a work method called DoSomething.
I implement MS's asynchronous pattern and provide a BeginDoSomething,
DoSomething, and EndDoSomething, which provide the non-GUI threaded behavior.

I often will have a class called UiSafeLowLevelWorker that takes as a
constructor the LowLevelWorker instance and the Control. This user-
interface safe wrapper uses Invoke and Events to marshall the calls
to the GUI thread.

I've also done it on a method-by-method basis. In this case, my
LowLevelWorker class will have a method (in addition to the ones
already listed) call UiSafeDoSomething that raises GUI-safe events.

Food for thought,
Tom
 
J

John Saunders

Keeping it on the same thread is what people are used to from the Framework,
so I'd suggest keeping it that way. Maybe you could then add something to
make it easier for a beginner to then properly marshall the event to the
message pump. Something cleaner than Control.Inoke, I mean.
 
C

Chris Tacke, eMVP

On the plus side, doing the move did get Exceptions marshalled across so
they can now be caught on the calling thread (they actually just become
OnError events). I'll move the rest back in the next release.

--
Chris Tacke, eMVP
Co-Founder and Advisory Board Member
www.OpenNETCF.org
---
Windows CE Product Manager
Applied Data Systems
www.applieddata.net


John Saunders said:
Keeping it on the same thread is what people are used to from the Framework,
so I'd suggest keeping it that way. Maybe you could then add something to
make it easier for a beginner to then properly marshall the event to the
message pump. Something cleaner than Control.Inoke, I mean.

--
John Saunders
John.Saunders at SurfControl.com

Chris Tacke said:
It does now. Originally it threw them in the context of the receiving
thread, which caused some users problems if they wanted to update the UI
right from the event handler. Of course your argument for keeping the
handlers on a separate thread are well taken, and now I'm undecided which
way I should go. I think moving it *back* to the thread is probably
better - I was just trying to make life easier for beginners, but in doing
so I think I may have crippled functionality. Intersting thought - thanks
for bringing it up!

--
Chris Tacke, eMVP
Co-Founder and Advisory Board Member
www.OpenNETCF.org
---
Windows CE Product Manager
Applied Data Systems
www.applieddata.net


Daniel Moth said:
Hi

Interesting... Do you mean that the serial class throws events on the GUI
thread by default?

I've always thought it is a mistake for a low level server component
(e.g.
a
SerialPort) to raise events on the GUI thread. Most users will want to
process the data (a stream of) on a background thread and occasionally
update the GUI. At that moment (or whenever), using Control.Invoke is easy
client-side... MS must agree with me since that is the way the socket and
serial classes work... At the very least there should be an option not to
use a Control internally in the class (much like System.Timers.Timer uses
the SynchronizingObject property by implementing the ISynchronizeInvoke)...

Note that I have no interest which way the implementation of the specific
serial class goes but I was just intrigued with the design decision at a
general level...

Cheers
Daniel


"Chris Tacke, eMVP" <ctacke[at]Open_NET_CF[dot]org> wrote in message
Take a look at the latest. I've fixed it.

-Chris

Hi Chris,

I went through and re-did the events in the OpennETCF.IO.Serial.Port
class
based on this exact same problem recently, so if you're after an
example
of
one way to marshal the events to the primary thread it would do.

I looked at the code, but, if event handler code always runs in
the
same
thread that fired the event (dixit Jon), then I don't see how it would
accomplish marshalling events from the CommEventThread to the primary
thread.

E.g. from inside your CommEventThread you fire an event
m_DataReceived(). This will invoke the event handler
Port_m_DataReceived, whose code will still run inside the
CommEventThread. Inside the event handler you invoke another set of
event handlers, but surely, these TOO will run in the CommEventThread
context?!

I.e. what part of the code exactly will make the e() call run on the
primary thread?


Regards,

Elisa
 
R

Ravichandran J.V.

Could you possibly look at changing the whole approach to your Observer
design pattern ? Like applying the events of the clients to a Socket
object rather than through the GUI like a form.

For instance, each client that gets attached to the server could be
represented as an event because the client is going to connect to a
socket object and hence, each socket object could represent an event.

with regards,


J.V.Ravichandran
- http://www.geocities.com/
jvravichandran
- http://www.411asp.net/func/search?
qry=Ravichandran+J.V.&cob=aspnetpro
- http://www.southasianoutlook.com
- http://www.MSDNAA.Net
- http://www.csharphelp.com
- http://www.poetry.com/Publications/
display.asp?ID=P3966388&BN=999&PN=2
- Or, just search on "J.V.Ravichandran"
at http://www.Google.com
 

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