Waiting on a Thread - Revisited

C

Charles Law

Hi guys. I'm back on the threading gig again.

It's the age-old question about waiting for something to happen without
wasting time doing it.

Take two threads: the main thread and a worker thread. The worker thread is
reading the serial port, waiting for something to happen (a service
request). When it does it raises an event. Of course, the event is executed
on the worker thread. The idea is that when the event is raised, the handler
issues a command on the serial port and waits for a response. The problem is
that the part of the worker thread that does the listening (for replies) is
tied up with the event it has just raised, and therefore cannot listen for
the latest reply.

So, I think that when the event is raised, I need to set a flag perhaps,
that can be picked up on the main thread. This way the event completes, the
worker thread goes back to listening for replies, and the main thread sees
the flag and issues its command.

Sounds good, but now I have to periodically check for the flag in the main
thread. That sounds an awful lot like polling to me, and I don't want to
waste time polling.

How can I catch the flag in the main thread when it changes, without having
to sit and wait for it?

As usual, any suggestions about how else to do this are always welcome,
however radical.

TIA

Charles
 
C

Cor Ligthert

Hi Charles,

When I see your problem my answer is direct remoting, however maybe this can
also done by a threading program. It is a problem old as hell. There is in
my opinion needed a stack.

So why not create a stack using an arraylist.

You start your sub tread every time something is done from the first row of
that arraylist (when the tread is not active you can polling the arraylist
using the thread.threading.sleep if there is something) and delete that
item it is done.

While you add every time to the last row when there is something to be done,
this simple solution would work in my opinion

Cor
 
J

Jon Skeet [C# MVP]

Sounds good, but now I have to periodically check for the flag in the main
thread. That sounds an awful lot like polling to me, and I don't want to
waste time polling.

How can I catch the flag in the main thread when it changes, without having
to sit and wait for it?

As usual, any suggestions about how else to do this are always welcome,
however radical.

I'm afraid I didn't follow your example very closely, but it sounds
like you basically want Monitor.Wait and Monitor.Pulse.

I've got an unfinished article which talks about them (and other
things) - it's at
http://www.pobox.com/~skeet/csharp/multithreading.html

There's more to come when I get round to it, but the bit in "More
Monitor methods" described Wait and Pulse.

(You could also use ManualResetEvent or AutoResetEvent.)
 
C

Charles Law

Hi Cor

I have just read Jon's article on multi-threading in .NET and I now
understand how the Wait and Pulse methods work, so I am going to try that.
It looks like just the job.

Thanks for your suggestion though, as I think it is going to help me in
another area, related to the same task.

Charles
 
C

Charles Law

Hi Jon

I have just read your article and the mud has cleared (a little). I have
created another thread to respond to service requests, so as not to hold up
my main thread, and used the Wait and Pulse methods to signal between the
worker thread and the new thread. Just a few refinements to make and it'll
be there ... ;-)

Cheers.

Charles
 
C

Charles Law

Hi Jon

I have implemented a solution using SyncLock, Wait and Pulse, and all is
well. My CPU time has gone down from 30% to nil, which always cheers me up
:)

However, I am noticing some odd behaviour. My previous solution used a do
loop, with DoEvents in it and a test for my flag, whereas the current
solution calls

Monitor.Wait(myflag, 100)

to wait for 100ms before returning.

Using DoEvents, I could click on a checkbox on-screen and it would change
state with each click. Now, using Monitor.Wait, I have to click the box
several time before it changes state. It's as if the UI is not getting time
to service the clicks.

Is that behaviour you would expect using Monitor.Wait?

At this point I have three threads running: the main UI thread, a comms
thread that listens to the serial port, and a thread that waits for service
requests from the comms thread. The comms thread call Monitor.Pulse(myflag)
whilst the service request thread call Monitor.Wait. On that basis, I would
expect the UI thread to be unhindered, but that does not seem to be the
case.

Charles
 
A

AlexS

Hi, Charles

if you use Wait on UI thread - that's the reason. Wait passes effectively
control out of calling thread, so it's even worse than DoEvents in this
respect. If you use lock on UI thread on same object(s), which are used in
Monitor.Wait - that's one additional reason.

I lost track of original questions/answers, so can recommend only - remove
Wait from UI thread and check what and where you lock. Attach event to
thread object, assign UI thread delegate to event when constructing thread
and use Pulse in UI thread and Wait in worker thread. Minimize time spent in
lock sections.

Take a look at examples at
http://msdn.microsoft.com/msdnmag/issues/03/02/Multithreading and in MSDN
also, if you haven't seen them yet.

HTH
Alex

Charles Law said:
Hi Jon

I have implemented a solution using SyncLock, Wait and Pulse, and all is
well. My CPU time has gone down from 30% to nil, which always cheers me up
:)

However, I am noticing some odd behaviour. My previous solution used a do
loop, with DoEvents in it and a test for my flag, whereas the current
solution calls

Monitor.Wait(myflag, 100)

to wait for 100ms before returning.

Using DoEvents, I could click on a checkbox on-screen and it would change
state with each click. Now, using Monitor.Wait, I have to click the box
several time before it changes state. It's as if the UI is not getting time
to service the clicks.

Is that behaviour you would expect using Monitor.Wait?

At this point I have three threads running: the main UI thread, a comms
thread that listens to the serial port, and a thread that waits for service
requests from the comms thread. The comms thread call Monitor.Pulse(myflag)
whilst the service request thread call Monitor.Wait. On that basis, I would
expect the UI thread to be unhindered, but that does not seem to be the
case.

Charles
 
J

Jon Skeet [C# MVP]

Charles Law said:
I have implemented a solution using SyncLock, Wait and Pulse, and all is
well. My CPU time has gone down from 30% to nil, which always cheers me up
:)

However, I am noticing some odd behaviour. My previous solution used a do
loop, with DoEvents in it and a test for my flag, whereas the current
solution calls

Monitor.Wait(myflag, 100)

to wait for 100ms before returning.

Using DoEvents, I could click on a checkbox on-screen and it would change
state with each click. Now, using Monitor.Wait, I have to click the box
several time before it changes state. It's as if the UI is not getting time
to service the clicks.

Is that behaviour you would expect using Monitor.Wait?

At this point I have three threads running: the main UI thread, a comms
thread that listens to the serial port, and a thread that waits for service
requests from the comms thread. The comms thread call Monitor.Pulse(myflag)
whilst the service request thread call Monitor.Wait. On that basis, I would
expect the UI thread to be unhindered, but that does not seem to be the
case.

I'm not sure what you're doing in your UI thread - I would strongly
suggest not having a Monitor.Wait in your UI thread at all, nor having
calls to Application.DoEvents(). The UI thread should solely be for UI
actions.

What are you doing on the UI thread other than short-running UI
operations?
 
C

Charles Law

Hi Alex

What I was trying to say was that there is no Wait in my UI thread. That is
why I am surprised by the effect. The threads that use monitor are the comms
thread and the service request thread.

Charles


AlexS said:
Hi, Charles

if you use Wait on UI thread - that's the reason. Wait passes effectively
control out of calling thread, so it's even worse than DoEvents in this
respect. If you use lock on UI thread on same object(s), which are used in
Monitor.Wait - that's one additional reason.

I lost track of original questions/answers, so can recommend only - remove
Wait from UI thread and check what and where you lock. Attach event to
thread object, assign UI thread delegate to event when constructing thread
and use Pulse in UI thread and Wait in worker thread. Minimize time spent in
lock sections.

Take a look at examples at
http://msdn.microsoft.com/msdnmag/issues/03/02/Multithreading and in MSDN
also, if you haven't seen them yet.

HTH
Alex

Charles Law said:
Hi Jon

I have implemented a solution using SyncLock, Wait and Pulse, and all is
well. My CPU time has gone down from 30% to nil, which always cheers me up
:)

However, I am noticing some odd behaviour. My previous solution used a do
loop, with DoEvents in it and a test for my flag, whereas the current
solution calls

Monitor.Wait(myflag, 100)

to wait for 100ms before returning.

Using DoEvents, I could click on a checkbox on-screen and it would change
state with each click. Now, using Monitor.Wait, I have to click the box
several time before it changes state. It's as if the UI is not getting time
to service the clicks.

Is that behaviour you would expect using Monitor.Wait?

At this point I have three threads running: the main UI thread, a comms
thread that listens to the serial port, and a thread that waits for service
requests from the comms thread. The comms thread call Monitor.Pulse(myflag)
whilst the service request thread call Monitor.Wait. On that basis, I would
expect the UI thread to be unhindered, but that does not seem to be the
case.

Charles


the
main
want
 
C

Charles Law

Hi Jon

I was halfway through a response about not having a wait in my UI thread
when it dawned on me what I am doing. I will have to rethink this.

Thanks.

Charles
 
C

Charles Law

Alex

A correction. I have just realised that I have fallen victim of my own
attempt to oversimplify the problem. I am indeed using wait in my UI thread,
which is not what I had intended. The words drawing, board and back spring
to mind ;-)

Charles


AlexS said:
Hi, Charles

if you use Wait on UI thread - that's the reason. Wait passes effectively
control out of calling thread, so it's even worse than DoEvents in this
respect. If you use lock on UI thread on same object(s), which are used in
Monitor.Wait - that's one additional reason.

I lost track of original questions/answers, so can recommend only - remove
Wait from UI thread and check what and where you lock. Attach event to
thread object, assign UI thread delegate to event when constructing thread
and use Pulse in UI thread and Wait in worker thread. Minimize time spent in
lock sections.

Take a look at examples at
http://msdn.microsoft.com/msdnmag/issues/03/02/Multithreading and in MSDN
also, if you haven't seen them yet.

HTH
Alex

Charles Law said:
Hi Jon

I have implemented a solution using SyncLock, Wait and Pulse, and all is
well. My CPU time has gone down from 30% to nil, which always cheers me up
:)

However, I am noticing some odd behaviour. My previous solution used a do
loop, with DoEvents in it and a test for my flag, whereas the current
solution calls

Monitor.Wait(myflag, 100)

to wait for 100ms before returning.

Using DoEvents, I could click on a checkbox on-screen and it would change
state with each click. Now, using Monitor.Wait, I have to click the box
several time before it changes state. It's as if the UI is not getting time
to service the clicks.

Is that behaviour you would expect using Monitor.Wait?

At this point I have three threads running: the main UI thread, a comms
thread that listens to the serial port, and a thread that waits for service
requests from the comms thread. The comms thread call Monitor.Pulse(myflag)
whilst the service request thread call Monitor.Wait. On that basis, I would
expect the UI thread to be unhindered, but that does not seem to be the
case.

Charles


the
main
want
 
J

Jon Skeet [C# MVP]

Charles Law said:
What I was trying to say was that there is no Wait in my UI thread. That is
why I am surprised by the effect. The threads that use monitor are the comms
thread and the service request thread.

So what is the UI thread doing, do you know? It might be worth breaking
into the app in debug mode while it's being unresponsive, and see if
you can see where the UI thread is.
 
J

Jon Skeet [C# MVP]

Charles Law said:
A correction. I have just realised that I have fallen victim of my own
attempt to oversimplify the problem. I am indeed using wait in my UI thread,
which is not what I had intended. The words drawing, board and back spring
to mind ;-)

:)

Don't worry about it - threading is a tough nut to crack, and you
*always* have to be wary. (I squashed a deadlock bug today and felt
rather victorious - until I started wondering whether we've got any
others.)

If we can help any more, just ask - it often helps just to post your
potential plan of action, as then you tend to spot the flaws (if any!)
about 10 seconds after posting it. At least, that's my experience...
 
C

Charles Law

Hi Jon

I have been confusing two different bits of kit attached to the serial
ports. One is a long standing item that has a complicated path between UI
and comms. The other, which I added a couple of days ago, has a more direct
connection, and uses an ASCII protocol. The latter is the one that raises
service requests, and seems to be working fine. Having added it
successfully, I returned to the original item and thought I would 'improve'
it's operation by using SyncLock and Monitor.Wait/Pulse. What I failed to
appreciate was that the old kit was communicating straight off the UI
thread, so when I changed to using Monitor.Wait instead of a timeout loop
with DoEvents, the UI suddenly started behaving badly.

....

Actually, now I think about it, I was right the first time: my UI thread
does _not_ use Wait. I have a polling thread as well (you must think I don't
know what I am doing). The polling thread sends commands to the original
item and waits for a reply. It waits using Monitor.Wait and the comms thread
pulses to alert the polling thread when a reply has been received.
Therefore, my UI thread is just sitting in the normal message loop, waiting
for the user to click something.

When I use the timeout loop with DoEvents in the polling thread, the UI is
responsive. When I use Monitor.Wait in the polling thread, the UI starts to
play up, taking several clicks to change a checkbox state. [I should add at
this point that with each click of the checkbox, a command is sent to the
serial port and on to the external hardware. The polling thread retrieves
status information, one bit of which indicates whether the checkbox should
be checked or not. I have to click several times before the hardware sends a
status message showing that it received the command].

What is odd is that the it works smoothly when I use the timeout loop with
DoEvents, but not when I use Monitor.Wait.

I think I am going to have to draw a picture of what is happening - this is
doing my head in.

Charles
 
C

Cor Ligthert

Hi Charles,

And comes my solution again in picture?

I have thought your problem over as well, now I know I do it like that I
told, however I use the listview as the stack container.

And it works very fine.

Cor
 
C

Charles Law

Hi Cor

I am going to look at that again too. The idea of a stack, or queue seems a
good one. I will need some way of queuing replies as well, and tagging them
to the outgoing message, but then I think it will be very neat.

Charles
 
J

Jon Skeet [C# MVP]

Charles Law said:
I am going to look at that again too. The idea of a stack, or queue seems a
good one. I will need some way of queuing replies as well, and tagging them
to the outgoing message, but then I think it will be very neat.

A queue is likely to be more useful to you than a stack, unless you
*really* want to process things in a strange order :)

The page I pointed you at before
(http://www.pobox.com/~skeet/csharp/multithreading.html) happens to
provide an example of a producer/consumer system based on a queue - it
may well be useful to you.
 
C

Charles Law

Hi Jon

I think you are right. I slept on it and it is taking shape in my mind. I
already have a class that constructs messages and deecodes replies, and it
seems the obvious place to add a new method, that can be executed as a new
thread, to monitor a queue and despatch messages. My main thread can then
post a message, pulse the queue, and then go back to what it was doing.

I'll post back when I have it working ... I could be gone some time ;-)

Charles
 
C

Cor Ligthert

Hi Charles,

You are right the word is queue, however for me a stack is a first In first
Out queue and I am using for a First In First Out queue as well the word
stack, however queue should be the word. (Queue is a difficult word for me
to write maybe because it looks so much on the French "What")

However, for you as an Englishman queue means more, I once was early in
London very early on the station, and there where all people waiting nice in
a queue. Than there came some people who went to the front of the queue, I
said to my friend "probably Dutchman", and I was right. Therefore, you see
it has here a different meaning.

:)))

For who does not know this I am a Dutchman.

Cor
 
C

Charles Law

Hi Cor

We are very attached to our queues, and all they do is upset us - we spend
all our time worrying about whether someone else is pushing in, and looking
round franticly to make sure there isn't.

There is a British comedienne - Victoria Wood - who describes a situation
where a young couple on a train start kissing. The other people in the
carriage smile indulgently. Then the couple become more amorous, and the
other people in the carriage become more uncomfortable; but they say
nothing. The couple begin to remove each other's clothing, but still the
other passengers say nothing. Then, the couple start to make love, and the
other passengers just put their heads down and become ever more engrossed in
their reading matter.

Finally, when the couple have finished, the young man sits back and lights
up a cigarette, with which a woman calls over indignantly "I think you'll
find this is a non-smoking carriage".

Only on a British train, eh?

Charles
 

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