WAIT.APP

This program shows how to use true threads in Clarion and specifically how to use an Event that a Thread should wait on.

Note: Beginning with Clarion 6, True Background Threads can be created using the Clarion Start procedure. See the Notes section at the end of this document for Clarion 6 specific information.

A thread in this discussion is a Background Procedure that is started with the Windows API and not the Clarion Start() procedure.

Running a background Thread in Clarion is easy just so long as you don't use any Clarion Functions that rely upon an Accept Loop. This means you actually can Start a Background Thread that does this:

Loop
End

and your Clarion program will continue to run. If you try to Start() the same procedure using Clarion, your program will come to a halt (Clarion versions prior to 6). This is because Clarion threads use cooperative multi-tasking which depends upon an Accept Loop to operate properly.

When using true threads, you can not use any Clarion function that needs an Accept Loop (this rules out all Window Related Procedures and Functions). If your Thread has something to display, then Post a Message to some other Clarion Procedure and let it display the message.

In this Example, we are doing two things:

  1. Starting a Background Thread
  2. Waiting for an Event to Occur

The Thread is the Procedure that does the waiting for the Event.

The Event that the Thread is "waiting for" is a change in the current directory. Whenever a file in the current directory has been modified, the Thread will "wake up" and Post a Message to the Main Window to tell the Main Thread to update its Status Bar.

The Main Thread is actually the one that is updating the File that the Background Thread is "waiting on"!

Why not just use a Timer Event?

The Thread that is running uses no Processor ticks and is not taking up any of the Program's time slice. It runs in the background until Windows wakes it up (it uses no clock ticks and doesn't generate any Messages to the message queue).

With a Timer Event, the Event will fire off on the Interval you set. In this case, the Timer Event will have to check the Directory to see if anything has changed. Why check if nothing has changed?

Timer Events are a work-around. They are not a solution. Especially for a disk intensive Thread such as this example. Windows has the solutions, its just a matter of using them correctly in our Clarion Programs.

Program Description

  1. In the OpenWindow Event, the Main procedure retrieves the Main Thread ID for use by the Thread so that it knows which thread handle to post Event Notification to.
  2. An Event (EventHandles[2]) is created so that we can later force the thread to "wake up". We will need to signal this event when the application closes. The thread is mainly concerned with changes occurring in the directory that it is monitoring. When the program exits, the thread will likely be "asleep", waiting on a change to the directory. If the program exits while the thread is asleep, the process will remain in memory even though it "appears" to have been shut down.
  3. In Clarion 6, the Start() procedure is used to create the thread. In Clarion 5, we must use the CreateThread API to create the thread.
  4. When the WaitOnChange thread is invoked, it creates an Event that will be signaled when a change to the directory structure occurs (a file is created or modified). The Event Handle is stored in the EventHandles array and we then enter into an "endless loop" where we invoke the WaitForMultipleObjects API. This call will put our thread to sleep, where it will remain until either one of two events occur:
  1. A change to the directory occurs, or
  2. The second event, EventHandles[2], is signaled by the main procedure when the program shuts down.

Upon "waking up", the thread first checks if the application is closing (either the variable AppClosing is true and/or the return value from WaitForMultipleObjects is set to 1 (meaning the second event caused it to return). If the App is closing, the thread returns and the program will no longer be notified of Directory Changes.

If the App is not closing, the thread posts an Event to the main procedure to tell it to update its Status Bar. The thread then resets the change notification event and goes to the top of the loop to repeat the process.

  1. The Timer Event in the main procedure fires every 5 seconds. Its sole purpose is to update the watchme.txt file. Whenever this file is updated, the WaitForMultipleObjects function call in the thread will return, causing the thread to "wake up". The thread will post a user defined event to the main procedure which tells it to update its status bar. This Event Handler in the main procedure is where you would add your own code to process directory change notifications.

Clarion 6 Notes

Clarion 6 implements true, preemptive, multi-tasking threads. These are the same types of threads we would create using the Windows API. In the Clarion 6 wait.app program, we use the Clarion Start() procedure instead of the CreateThread API. This is the only difference between the Version 5 and Version 6 applications. Clarion 6 finally alleviates the need for Timer Events to wait for something to occur.

Kenny Gardner
GAP Development Company
http://www.gapdev.com/
February 9, 1999
Updated, September 27, 2004