Re: Code executing too fast -- causes errors



Thank you Jezebel,

There is clearly something fundamental I'm not understanding here, so please
bear with me.

(a) At any point in time there is a single thread running - in a single
processor environment this is by definition. This will run until it cedes
control (or, occasionally, Windows interrupts it).

(b) At the same point in time there are many other threads waiting for their
turn to run (according to priority) - again, essentially, a given.

(c) As far as I can tell from what you say, at the same point in time there
is also a queue of messages (or events) waiting to be processed. And this is
entirely separate from the threads waiting in (b) above.

So what happens when a message on the queue is processed? Might a thread get
(re)started?
If so, is it somehow queue jumping over the threads waiting in (b)
above?
If not, presumably it is added to the pool in (b) above.

If a thread doesn't get started in response to being processed from the
queue - as you are suggesting is the case with some events when a sleep is
in progress - what does happen to that message/event?

--
Enjoy,
Tony

"Jezebel" <warcrimes@xxxxxxxxxxxxxx> wrote in message
news:eeMYr5nSGHA.4752@xxxxxxxxxxxxxxxxxxxxxxx
No, you're only half understanding what's going on. DoEvents does indeed
process the message queue -- on completion (or if the queue is empty)
control returns to the line following the DoEvents. Threads are not added
to
the message queue -- only events.

As you say, sleep suspends execution for a given duration, then resumes
provided other threads do not have higher priority at that moment. (The
sleep interval is thus a minimum, not an exact amount.)

The key difference between the two approaches is that DoEvents will permit
other actions within your own app to run (eg if the user clicks buttons,
closes forms, etc). Sleep doesn't do that: no other code within your app
will be initiated during the Sleep call.





"Tony Jollans" <My Forename at My Surname dot com> wrote in message
news:e9uQvRnSGHA.4384@xxxxxxxxxxxxxxxxxxxxxxx
Sleep will indeed do that --
-- and, as you say, avoids the risk of unexpected events getting
processed, or conversely, eliminates the need to code for all possible
events.

I didn't think I said that at all. Indeed the point of my post was to
ask
whether that was the case. Let me try to be clearer.

My (limited) understanding is that:

DoEvents stops processing of the current thread in order for the system
to
process the message queue (I'm not sure of terminology but I think we
all
know what we mean by this). It takes as long as it takes. The current
thread
is eligible for restart when the message queue has been processed. In
effect, if not in fact, the first thing that happens with DoEvents is
that
the current thread restart is added to the end of the message queue.

Sleep stops processing of the current thread for an explicit amount of
time.
During that time the system can do whatever it wants but I would expect
it
to process the message queue. In theory the current thread could restart
before the whole of the message queue had been processed but I doubt
that
Windows tries to be that clever and I suspect that the current thread
restart is added to the end of the message queue when the specified time
has
elapsed.

I don't know how Windows operates and it may have multiple queues but I
have
never seen anything which suggests so. Whenever any process cedes
control
to
the operating system it must be aware of what may happen and, if
necessary,
be coded to handle it. This would seem to be as true wth Sleep as with
DoEvents.

It seems to me that, in waiting for an external process to finish,
Jonathan
is running a random (hopefully sufficient) number of DoEvents and you
are
suggesting a random (hopefully sufficient) number of Sleeps of a random
length. Both of you have determined what works by a process of trial and
error ('testing'). What is the difference? In both cases I think there
ought
to be APIs which would be more precise but it probably isn't worth the
complexity of coding them.

--
Enjoy,
Tony

"Jezebel" <warcrimes@xxxxxxxxxxxxxx> wrote in message
news:e6XamFkSGHA.5468@xxxxxxxxxxxxxxxxxxxxxxx
Of course you sometimes need to pause a macro and wait for something
else
to
finish. Sleep will indeed do that -- that's one of its main purposes
(as
opposed to DoEvents, which is specifically for processing the event
queue) -- and, as you say, avoids the risk of unexpected events getting
processed, or conversely, eliminates the need to code for all possible
events.

I recently had to deal with some code that created, then despatched,
PDFs.
The problem was knowing when the PDF is created, because Doc.Printout
returns control as soon as Acrobat has finished with the Word document;
the
finalisation of the PDF happens asynchonously. The code used was
something
like ...

... printout
LoopCount = 0
Do
Sleep 550
Check if PDF exists: if yes, exit do
LoopCount = LoopCount + 1
If LoopCount > 5 then
err.raise .... something has gone wrong
End if
Loop

The 550 (or whatever it was) was arrived at by testing, to find the
value
that achieved the lowest aggregate time - normally the loop iterated
just
once. (An even better solution is to use the Acrobat APIs so you *know*
when
the process is complete.)



"Tony Jollans" <My Forename at My Surname dot com> wrote in message
news:%234bbAgiSGHA.1204@xxxxxxxxxxxxxxxxxxxxxxx
Hi Jezebel,

Is there a way of pausing a macro to allow another process to finish
(humour
me and accept that it might be required on occasion) without ceding
control
to the system and letting it run whatever it sees fit? Won't sleep
(for
example) have the same effect except that it will also have an
explicit
amount of time before the process becomes eligible to be restarted.
There
is
no command that says 'selectively run other processes' or 'run other
processes except those that involve my parent' (or my children), is
there?

--
Enjoy,
Tony

"Jezebel" <warcrimes@xxxxxxxxxxxxxx> wrote in message
news:#w5HWWiSGHA.5736@xxxxxxxxxxxxxxxxxxxxxxx


Also, please explain to me what you have against DoEvents. Your
one
post
expressing reasons said that it "is an extremely dubious practice
(unless
you're also diligently switching off every possible source of
interfering
input ...)", but when I have an example that *did* have a source
of
input
(the option to click the Stop button) you said that using DoEvents
in
that
context was the right thing to do.



The danger with DoEvents is that it processes ANY event in the
queue,
not
just the ones you're necessarily expecting. It's not that you
shouldn't
use
it; but that you need to use a lot of care when you do -- a lot more
than
'scattering a few DoEvents around the application' implies.

To see the risk, here's a version of the example you posted a while
back.

1. Create a form with two buttons and add this code --

Private mCharVal As Long

Public Event StopNow()

Private Sub UserForm_Initialize()
mCharVal = 65
End Sub

Private Sub CommandButton1_Click()

mCharVal = mCharVal + 1
With New Class1
Set .CallerForm = Me
.InsertChar mCharVal
End With

End Sub

Private Sub CommandButton2_Click()
RaiseEvent StopNow
End Sub


2. Create a class module with this code --

Public WithEvents CallerForm As UserForm1
Private mCancelled As Boolean

Public Sub InsertChar(CharVal As Long)

Do Until mCancelled
ActiveDocument.Range.InsertAfter Chr$(CharVal)
DoEvents
Loop

End Sub

Private Sub CallerForm_StopNow()
mCancelled = True
ActiveDocument.Range.InsertAfter "Stopping" & vbCr
End Sub



Now run the form. Click Button 1. Click it again. And Again. Now
close
the
form by clicking the X at top right, without clicking button 2. This
is
obviously a trivial example, but you can see how sort of disasters
that
can
ensue from the indiscriminate use of DoEvents -- in this example, as
with
your original version, you need to do things like disable button 1
while
mRunning is true, and broadcast the form terminate event so the
spawned
classes don't run for ever.












.


Loading