See WARNING at end of document.
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.
The first Example (wait.app) shows how to wait for an external event to occur. In that example, the event is triggered by a file being updated in a specific directory.
In this Example, we are also waiting for an event to occur. The program uses a Generic Event, but it could be any Event such as waiting for a Program or Thread to terminate, waiting for a Memory Variable to change state, waiting for a Communications Event to occur, or any Event that Windows supports.
Rather than waiting for a file to be updated, this example waits for the specified event to occur, and then it updates a Data file. The updating is done within the Background Thread itself. After writing a new record to a TPS file, the Thread then Posts a message to a Clarion started procedure which contains a File Loaded Browse Box. Upon receiving this message, the Browse Box updates itself to show the newly added record.
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.
Upon "waking up", the thread first checks if the application is closing and, if so, it returns without doing any further processing.
If the App is not closing, the thread writes a record to the data file and then posts an Event to the main procedure to tell it to update its Status Bar. The thread then goes to the top of the loop to repeat the process.
Although it appears that this example is reading and writing to a Data File at the same time, it is not.
The Reading from the file doesn't occur until after the Thread Writes to the file and Posts a message to the Browse Box to tell the Browse to re-read the file and update itself.
Do not, under any circumstances, utilize the techniques in this Example Program with critical data files until you have thoroughly tested with a real life application.
We do not know what will occur if an Update Procedure is added to the Browse Box such that a user can Update the database file at the same time the Thread is also updating it.
The File Structure is declared with the Thread attribute. This means the Window Procedure that is displaying the data has a Private Copy of the File Buffer and the Thread is using the Global File Buffer.
Since this is a True Thread that is time sliced right along with your main program, data corruption can occur if Global Variables are used (and this includes the Clarion Runtime Library).
When the Thread wakes up because the Event it is waiting for occurs, your main program could be right in the middle of a String Assignment, File Update, or anything else.
Since we do not know if the Clarion Library is re-entrant, play it safe and do lots of testing (with non-critical data files).
These warnings are not as critical with Clarion 6 since the run time library is now re-entrant and you have critical sections and semaphores to protect your data.
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 fileupd.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