Threads and Events

  • Thread starter Thread starter Elisa
  • Start date Start date
E

Elisa

Hi,

Still trying to see the light through all this multi-threading madness...

Events are always handled in the same thread as they are raised, not?


Regards,

Elisa
 
Elisa said:
Still trying to see the light through all this multi-threading madness...

Events are always handled in the same thread as they are raised, not?

Not entirely sure what you mean - but just firing a delegate (in the
obvious way) does indeed fire it on the same thread.
 
That's entirely up to you. A named event is global, so you can call
CreateEvent( "name" ) in thread 1 and CreateEvent( "name" ) in another
thread *or process*. They will have references to the same event, so either
can set or reset the event, and either can wait on it.

Paul T.
 
Paul G. Tobey said:
That's entirely up to you. A named event is global, so you can call
CreateEvent( "name" ) in thread 1 and CreateEvent( "name" ) in another
thread *or process*. They will have references to the same event, so either
can set or reset the event, and either can wait on it.

Your response and mine have been talking about radically different
kinds of events. I think we need some more details from Elisa here:
what kind of events were you talking about?
 
Hi,

Sorry about the confusion!

1. I have a method MyMethod() that handles event XXX (e.g. a method that
has a "Handles XXX" part or is used as a parameter in an "AddHandler
XXX, AddressOf MyMethod" call).
2. I have a thread that issues RaiseEvent XXX.

Then MyMethod() is running in the same thread as the thread with the
RaiseEvent call, not? I simply can't think of any other thread it might
be running in...

Continueing on the same subject, does RaiseEvent work synchronously or
asynchronously? I.e. does it immediately call all the event handlers,
one after the other, and wait until the last one finishes, or does it
just notifies the event handlers and continue without waiting for the
event handlers to finish their business?


Regards,

Elisa
 
Elisa said:
Sorry about the confusion!

1. I have a method MyMethod() that handles event XXX (e.g. a method that
has a "Handles XXX" part or is used as a parameter in an "AddHandler
XXX, AddressOf MyMethod" call).
2. I have a thread that issues RaiseEvent XXX.

Then MyMethod() is running in the same thread as the thread with the
RaiseEvent call, not? I simply can't think of any other thread it might
be running in...

I believe it's in the same thread, yes.
Continueing on the same subject, does RaiseEvent work synchronously or
asynchronously? I.e. does it immediately call all the event handlers,
one after the other, and wait until the last one finishes, or does it
just notifies the event handlers and continue without waiting for the
event handlers to finish their business?

Synchronously.
 
Hi,

OK, so events handlers are running in the same thread that issues the
RaiseEvent call, and the call waits for all the event handlers to finish.

So why doesn't my #@BLEEP%$-ing code work then! Aaargh!! :-(

Anyway, thanks for answering these questions!


Regards,

Elisa
 
Jon Skeet said:
I believe it's in the same thread, yes.

Hmm, I would think the event handler would run in the thread that created
the handler, not the event firer. Bear in mind I've not tested it, but it's
a good question. Here's how I think (and agin, it's my thinking, which is
often flawed):

Given the code below, wouldn't the MEssageBox be running in the same thread
as threadprocA, even though threadprocB raised it?


void threadprocA()
{
obj.myEvent += new MyDelegate(handler);
while(true) {DoEvents()};
}

void threadprocB()
{
while(true)
{
myEvent(this);
Sleep(1000);
}
}

void handler()
{
MessageBox.Show("Huh?");
}
 
Chris Tacke said:
Hmm, I would think the event handler would run in the thread that created
the handler, not the event firer.

How would that work? The thread that created the event handler may not
even exist any more, and if it *does* exist it may well not be running
anything like a message pump.
Bear in mind I've not tested it, but it's
a good question. Here's how I think (and agin, it's my thinking, which is
often flawed):

Given the code below, wouldn't the MEssageBox be running in the same thread
as threadprocA, even though threadprocB raised it?

Well, the MessageBox itself might be - I don't know exactly how
MessageBoxes work in terms of threading, but it would be the thread
running threadprocB which actually called MessageBox.Show.
 
Hi,

The event handler executes in the same thread context as that of the source
of the event. This event code executes synchronously.

Dick

--
Richard Grier (Microsoft Visual Basic MVP)

See www.hardandsoftware.net for contact information.

Author of Visual Basic Programmer's Guide to Serial Communications, 3rd
Edition ISBN 1-890422-27-4 (391 pages) published February 2002.
 
It's a damned good question, especially if the event handler needs to update
the UI. If it's in the context of the worker thread, the event handler
needs to call Control.Invoke, if it's in the primary thread context, then it
doesn't.

Your point that the thread that created the handler may no longer exist is a
good one, so I'm thinking now that you're probably right that it is in the
invoker's thread, not the creator's.

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

What problem are you having?

Are you having trouble marshalling data to the STAThread of a form? If you
attempt to update the UI directly from an event handler, the thread context
is wrong, and things proceed badly. You have to Invoke a delegate that
exectutes in the STAThread context. It is common to use Control.Invoke, but
I prefer Me.Invoke (or this, perhaps). You cannot pass data into this
delegate, because of the limited threading model that the Compact Framework
provides. So, you have to use some form of shared data (Private, for
example).

Here is code that I use for handling an OnComm event that is generated by
the ReadThread in my serial class:

Private Sub ReceiveEvent() Handles SerialPort.OnComm



ScreenBuff.Append(SerialPort.InputString)

'This is FAR from the best way to display (or manage) this data. It is
"quick and dirty."

Me.Invoke(New EventHandler(AddressOf DisplayData))

End If

End Sub

Private Sub DisplayData(ByVal sender As Object, ByVal e As EventArgs)

'This marshals receive data from the receive thread context (OnComm or
CommError) to the Windows Form STAThread context

With txtTerm

..Text = ScreenBuff.ToString

..SelectionStart = .Text.Length

If (ErrorMessage.Length > 0) Then

..SelectedText = ErrorMessage

ErrorMessage = ""

End If

End With

With ScreenBuff

If .Length > 0.8 * .Capacity Then

ScreenBuff.Remove(0, CInt(0.6 * .Capacity))

End If

End With

End Sub


Dick

--
Richard Grier (Microsoft Visual Basic MVP)

See www.hardandsoftware.net for contact information.

Author of Visual Basic Programmer's Guide to Serial Communications, 3rd
Edition ISBN 1-890422-27-4 (391 pages) published February 2002.
 
Chris Tacke said:
It's a damned good question, especially if the event handler needs to update
the UI. If it's in the context of the worker thread, the event handler
needs to call Control.Invoke, if it's in the primary thread context, then it
doesn't.

That's what Control.InvokeRequired is for - in the full framework!

I find that most of the time I know what the context is going to be
though - you can always provide two different methods, one which uses
Control.Invoke and one which doesn't. Name them appropriately, and call
them appropriately from the right context.
Your point that the thread that created the handler may no longer exist is a
good one, so I'm thinking now that you're probably right that it is in the
invoker's thread, not the creator's.

It's the only answer that I think really makes sense - you can't just
ask another random thread to stop what it's doing and execute something
else :)
 
Hi,

The problem I'm trying to solve is this:

I'm using the OpenNet.CF Serial IO code to talk to a R/F network. The
protocol that this R/F network uses, is asynchronous, in that you send
out a request, and at some point later on you get the response. The
consuming application is notified that the response has arrived by an
event that is raised inside the comms library (which runs in a
background thread).

But in my application, I want this to look as one method call, i.e. you
give it some parameters and you get a value back, without having to
worry that the underlying communication is asynchronous.

I'm attempting to implement the following architecture:

1. Main thread: set WaitingForResponse flag to True
2. Main thread: set ResponseHandled flag to False
3. Main thread: send request
4. Main thread: wait until WaitingForResponse flag is False, or time-out.
5. Comms thread: if response received, fire event
6. Comms thread: inside eventhandler, set WaitingForResponse flag to
False, and wait until ResponseHandled flag is True
7. Main thread: handle response
8. Main thread: set ResponseHandled flag to True

So I need to synchronize the main thread and the comms thread, as they
both share access to a couple of variables (e.g. the WaitingForResponse
flag, the ResponseHandled flag, the response itself, ...).

Sadly, because the .NET CF framework doesn't support any of the
..Wait(timeout) calls in its synchronization objects, things get more
complicated than they should be, you can't use the ManualResetEvent or
AutoResetEvent objects because your app might hang indefinitely if the
response is never received (a likely scenario in a R/F network).

I thought all that is required to get things synchronized are a couple
of SyncLock statements wherever I touch shared variables (e.g. the flags
mentioned above). But I still haven't got it to work correctly, hence my
questions about threading, to make sure that threads, SyncLock and event
handlers work the way I think they work.


Regards,

Elisa
 
Elisa,

What happens if you don't worry about synchronizing access to the
WaitingForResponse and ResponseHandled flags?
 
Hi,

The "easy" way to handle this is NOT TO use threading!

This is an interesting theoretical (and, at times heretical) concept.
Sending serial commands, and waiting for responses is an inherently a
single-threaded operation. Anytime you involve other threads in the process
you increase the complexity of the design, while decreasing its performance.
This is not good (IMO).

Here is my suggestion. Set the RThreshold property to 0. This means that
OnComm receive events ARE NOT GENERATED. Thus, you may simply poll the
InBufferCount property, or (my real preference) append new receive data to a
buffer, looking all the while for some terminating condition -- usually one
or more characters.

If you do not enable OnComm, there is no interaction between your polling
code and the background thread that in the serial object! Thus, you don't
need to use SyncLock/Monitor for locking or any other internal
communications mechanisms.

If you download my CFSerialIO example, you will find code in a command
button click event that does exactly what you want to do. It sends a
command and waits for a response.

I have lots of suggestions for when to use polling and when to use event
driven communications in my book (see below). Each has its "time-slot."
For this, I prefer polling.

Dick

--
Richard Grier (Microsoft Visual Basic MVP)

See www.hardandsoftware.net for contact information.

Author of Visual Basic Programmer's Guide to Serial Communications, 3rd
Edition ISBN 1-890422-27-4 (391 pages) published February 2002.
 
Back
Top