Multithreading and Waiting without Blocking

C

Charles Law

Consider the following scenario:

A data packet is sent out of a serial port and a return packet is expected a
short time later.

The application sending the packet needs to send another packet as soon as
the return packet has been received. It needs to wait for the return packet,
but time out if one is not received.

Whilst packets are being exchanged the application needs to be responsive.

To maximise throughput, should the packets be sent on a separate thread? How
would the application wait for the thread to complete (without blocking) in
order to send subsequent packets? Looping with DoEvents causes CPU % to
shoot up, and Sleep(x) introduces excessive delays between packets.

TIA

Charles
 
J

Jan

Charles,

Dependent on the method (an RS232 control, API-calls, ...) you use to
communicate with RS232, you might make use of an event or a callback
whenever return-data comes in.

Regards,
jan
 
C

Cor

Hi Charles,

I do it by just let the subthread raise an public event and set a handler
for that in the program that starts the thread.

What do I mis?

Cor
 
C

Charles Law

Hi Jan

I have an event that is raised when data is received, and I do my packet
detection there. This event is already on a separate thread, so once a
complete packet has been received I just set a flag to indicate the arrival.
My main send and receive thread needs to wait for this flag, but I don't
want to use excessive cpu time effectively polling the flag until it is set.
That is why I wondered about a wait on another thread, or something like
that.

Charles
 
C

Charles Law

Hi Cor

The reason I haven't done this is because the main thread needs to wait for
the return packet before sending the next packet out.

At some point, it seems to me, there has to be a wait in order to keep the
packets transferring synchronously.

I had thought of doing it something like this:

Application thread
------------------
Do
Wait for send thread to terminate
Start send thread to send packet
Loop

Send thread
------------
Send packet
Wait for return packet to be received; timeout if none received.
Terminate thread

but I cannot work out how to do this without wasting time polling the send
thread and blocking the application thread.

Charles
 
C

Cor

Hi Charles,

That is what I had in a program, but now it is just as beneath, I deleted a
lot and changed the Dutch a little bit to English

So it is just for the idea what I am doing, I hope I did not cut to much it
are more classes you know.

Cor
\\\
Application thread
Private WithEvents SendThread As New clsSendThread
Protected Sub threadReady() Handles SendThread.threadReady
do some things,
Sendthread.main()
End Sub
///
clsSendthread
Public Event threadReady()
main Sub
ThreadAThread = New System.Threading.Thread(AddressOf ThreadA)
ThreadAThread.Start()
end sub
Private Sub ThreadA()
Dim myfunction As New TheFunction()
doReady(myfunction.doyourthings)
End Sub
Private Sub doReady(ByVal errors As String)
do some things
RaiseEvent threadKlaar()
End Sub
///
 
J

Jan

Charles,

In case the required processing is not too extensive, you might just do it
in that event, instead of only setting a flag.

Regards,
Jan
 
C

Charles Law

Jan

The processing required is actually to send the next packet, and then wait
for a return packet. If I do this in the event I'm in danger of entering a
recursive spiral, as the event will be raised for the return packet,
whereupon I send out the next packet and wait for the return, and continue
to go deeper and deeper.

Charles
 
C

Charles Law

Hi Cor

I'm not sure I understand what happens here, but it looks like I would need
a wait in there somewhere whilst the return packet comes in. Otherwise, the
process would just run through and terminate and the next packet could get
sent out before the previous return packet had been received. Have I
misunderstood?

Charles
 
C

Cor

Hi Charles,

It are three classes.

The main class
A starter stopper class
A class that does the things in a thread (You do not see that , only the
declaration of it)

for me it looks very much as your problem.

Have a look for it, I have also something with a timer, but that is not what
you want I think.

Cor
 
D

Dominique Vandensteen

what you need is to wait on a monitor and send a pulse to that monitor when
something is arrived
you can set that you wait a max amount of time...
check out System.Threading.Monitor
I think that's the good way to do it

dominique
 
D

Dick Grier

Hi,

IMO, a separate thread for sending and receiving simply increases the code
complexity (at lot), with no performance improvement.

This scenario is common, and I have a number of examples that illustrate the
way that I tackle it in my book (see below). I combine BOTH
Application.DoEvents with Sleep(0) in a loop. This keeps the CPU% low, but
the application remains responsive. If you choose, you can tailor the
number of calls to DoEvents (for example, call DoEvents only every 10 times
through the loop).

If Sleep(0) causes too much delay between packets, then you are SOL. The
actual impact of Sleep(0) is indeterminate. However... It should be much
less than 1 mS.

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.
 
D

Dick Grier

Hi,

Using flags this way slows the process -- it does not speed it. (Again,
IMO). Simply send and receive in the same thread, employing as tight a
state machine as you can design.

It is easy to thing that multithreading might speed things up. It can, in
some cases, but this is not one of those cases. The inter-thread
communications needed is not free. In fact, it is quite expensive, when it
comes to measured performance.

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.
 
C

Cor

Hi Dick,

Charles is one of the main regulars from this newsgroups.
Not one who is always here, but belongs to the crew from this newsgroup.
He has questions and contributes.
It would be very strange if he did not know this.

Cor
 
J

Jan

Charles,

I'm not sure I understand the problem.

Everytime something (part of a return message) comes in, the event is fired.
Every event adds its incoming data to the already available data in a shared
variable, and checks whether the incoming message is complete. If not
complete, that's the end of the event... wait for the next event. If
complete, send out the next packet and clear the shared variable with the
completed-incoming-message. End of the event. Wait for the next event the
start with the next incoming data (= the next return packet). As far as I
see, this is not recursive... you're not getting deeper.

Only make sure that your event-processing is not interrupted by a next
event, as this will mess up the message in the shared variable.

If my understanding is incorrect, please feedback.

Regards,
jan
 
C

Charles Law

Jan

You have it correct, in so far as I keep servicing the receive character
events until the return packet is complete. At this point, I need to allow
further processing on the packet. The packet is unpacked as it bubbles back
up the caller chain. So the immediate caller needs to get the full packet,
from which it strips off the start and end characters and checks the BCC. If
correct, it returns the inner data to the caller back up the line, where the
content is checked for validity. Finally, the data is passed to the original
caller, where it is interpreted according to the command that was issued.

When that has all happened, the caller at the top of the chain issues
another command, down the chain, whereupon it is packaged up and sent at the
lowest level. Only then is another return packet received. The event that
receives incoming data, byte-by-byte is a long way from the caller where
commands are issued, and has no control over what commands are issued when.

In the above scenario, there is a wait at the lowest level, while the return
packet comes in. Only when it has been received can the low level return the
data back up the chain.

So, it is that wait at the low level that I am trying to eliminate, or at
least execute without consuming cpu time. If it is on another thread my app
remains responsive, but looping with DoEvents consumes cpu and a Sleep in
the loop means that I don't respond to the received packet at the earliest
possible moment.

Any thoughts?

Charles
 
J

Jan

Charles Law said:
Jan

You have it correct, in so far as I keep servicing the receive character
events until the return packet is complete. At this point, I need to allow
further processing on the packet.

Once the event sees that the "return package" is complete it (=the same
event-procedure) can do any required further processing , and in the end
(still in that same call/trigger of the same event-procedure) it can sent
the full packet back to the immediate caller. This ends this last
event-procedure-call/trigger.
The packet is unpacked as it bubbles back
up the caller chain. So the immediate caller needs to get the full packet,
from which it strips off the start and end characters and checks the BCC. If
correct, it returns the inner data to the caller back up the line, where the
content is checked for validity. Finally, the data is passed to the original
caller, where it is interpreted according to the command that was issued.

When that has all happened, the caller at the top of the chain issues
another command, down the chain, whereupon it is packaged up and sent at the
lowest level. Only then is another return packet received. The event that
receives incoming data, byte-by-byte is a long way from the caller where
commands are issued, and has no control over what commands are issued when.

In the above scenario, there is a wait at the lowest level, while the return
packet comes in. Only when it has been received can the low level return the
data back up the chain.

So, it is that wait at the low level that I am trying to eliminate, or at
least execute without consuming cpu time.

As all activity / processing is done within the multiple calls/triggers of a
single event-procedure, there is no wasted cpu-time consuming, and your app
will remain responsive for other activities all the time. The is NO polling
nor doevents, nor sleep required. And everytime a packet comes in, the
event is triggered, so processing is immediate and without wasted cpu

Hope this helps,
Jan
 
J

Jay B. Harlow [MVP - Outlook]

Charles,
In addition to the other comments.

What I do in my app is have a second thread that handles the serial port.

I use a System.Collection.Queue to maintain the list of packets to send.

I encapsulate the Thread, Queue, a "padlock" and an AutoResetEvent into a
class. The "padlock" is an object to single thread access to the Queue, the
AutoResetEvent is used to signal the serial thread that the main thread has
put items in the Queue.

The Main Thread calls a method on this class to place the packet into the
Queue, the serial thread reads a packet out of the Queue and sends it out
the serial port, the serial thread then waits for the response. The serial
thread will use Control.Invoke to raise events on the Main Thread when the
data is received. (I'm still working on the raise event on Main thread
piece). I plan on my class having a property of type
System.ComponentModel.ISynchronizeInvoke called SynchronizingObject (similar
to System.Timers.Timer) that will control where the "Main Thread" is to
raise the events...

I have previously posted how I setup the Thread & Queue, try
groups.google.com or post if you want the sample. I'm still working on
raising the event on the Main Tread. Oddly enough I started looking at
raising the event yesterday ;-)

In your situation I wonder if the Main Thread should own its own queue, and
use its notification event to ask the serial thread to send more data. In
this case I think I would have a variable in the class that identifies the
next packet instead of a queue of packets in the class...

Hope this helps
Jay
 
D

Dick Grier

Hi,
He has questions and contributes.
It would be very strange if he did not know this.
<<

I don't have any opinion about that. He asked, and I (attempted) to answer.
It always is possible that there is some sort of miscommunication.

Where I do have opinions (when it is/isn't appropriate to use threading), I
state them as opinions. They are based on hard experience, though.

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.
 

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

Similar Threads


Top