Home page Home page Home page Home page
Pixel
Pixel Header R1 C1 Pixel
Pixel Header R2 C1 Pixel
Pixel Header R3 C1 Pixel
Pixel
By Captain C | Thursday 4 November 2010 12:26 | 0 Comments
In this post we’re going to turn our attention to an old Arev subroutine called Delay() that can still be used in OpenInsight. It’s a simple function and is designed to halt a Basic+ program for a specified number of seconds before continuing again (full details can be found in the OpenInsight on-line help).

However, while Delay() made the transition to the Windows world, it still behaves in a fashion befitting its DOS/Arev heritage - i.e. it expects to run in a single, non-multitasking environment. Internally it simply sits in a tight until loop until the nominated interval has passed after which it returns. This is all well and good but on a modern OS this steals virtually all the CPU time, which is silly when you consider that the actual intent is to simply “do nothing”!

So, assuming that we actually want to introduce a delay of some sort into a program, what we really need to do is only put the actual OpenEngine thread (i.e. the thread that executes your Basic+ code) into a state whereby it uses no CPU processing time until the required interval has passed, after which processing can resume.

The Windows API has several functions for putting threads to “sleep”. i.e. putting them into a state whereby they use no CPU resources until they are “woken up” based one or more wake criteria, and we’ll begin by looking at the most simple of these called, appropriately enough, Sleep().


The Sleep() function

This is a very simple Windows API call that suspends the calling thread for at least the specified number of milliseconds. It is documented by Microsoft like so:

VOID WINAPI Sleep( DWORD dwMilliseconds );

Parameters

dwMilliseconds

The time interval for which execution is to be suspended, in milliseconds.

A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run. If there are no other threads of equal priority ready to run, the function returns immediately, and the thread continues execution.


Return Value

This function does not return a value.


(Full details on Sleep can be found at: http://msdn.microsoft.com/en-us/library/ms686298(VS.85).aspx, though we make no promises on the future validity of that URL as MSDN seems to get a new facelift far too often :)



Using Sleep()

As Sleep() is a Windows API function it must be prototyped before you can use it from Basic+. You can create your own prototype if you wish, but it is already included in OpenInsight, aliased with the curious name of "Sleepery" in the DLL_KERNEL32 prototype record so you may use that version if you prefer (Quite why Sleep() was aliased to Sleepery() is beyond your humble authors understanding, but I digress...)

(It is also available in our Windows API Library package, aliased as "WinAPI_Sleep", for those of you who have installed it into your systems. However, for this example we'll use the version installed with OpenInsight)

So the Sleep() function, on the surface, sounds ideal and we can write our new version of Delay() something like this:


compile subroutine DelayEx( delayTime )

   call sleepery( delayTime * 1000 ) ; * // Sleep works with milliseconds
   
return


If you test-run this function you’ll see that your CPU usage is kept at 0% during the Sleep() interval and everything appears fine... or does it?

Every thread in Windows has a message queue, and messages can be posted to this queue to interact with the thread (Forms and controls that are created by a thread also share its message queue, so any messages posted to them will end up here too). Unfortunately, during a Sleep() interval, the thread won’t check it’s message queue (or do anything else for that matter) which means that other clients relying on the result of the message may even appear hung, and this can happen readily in the case of programs which broadcast messages to every top level window in the system and wait for a response before continuing. You may well think that this won’t apply to OpenEngine, as it’s only running Basic+ code right? Wrong. Don’t forget OpenEngine has its own window (you know, the actual OpenEngine window with the list of executed commands and the ‘Debug’ and ‘Log’ buttons) and that window still exists even when you launch OpenInsight and specify that you don’t want a visible engine. It hasn’t gone anywhere – you just can’t see it!

So, what we need is a function that can put a thread to sleep for a defined period of time BUT has the capability to be awakened should a message need to be processed. The Windows API provides just such a function in the form of MsgWaitForMultipleObjects(), and this is something we’ll look at in the next post.

Labels: , ,

Pixel
Pixel Footer R1 C1 Pixel
Pixel
Pixel
Pixel