Thread
From Real Software Documentation
Threads execute code in the background.
| Events | ||
|
| Properties | ||||
|
| Methods | ||||||
|
Class Constants
Priority
The following class constants can be used to set the priority of the thread with the Priority property.
| Class Constant | Description |
|---|---|
| LowestPriority | Lowest priority |
| NormalPriority | Normal priority |
| HighPriority | High priority |
State
The following class constants can be used to test the state the thread is in by examining the value in the State property.
| Class Constant | Description |
|---|---|
| Running | The thread is running normally. |
| Waiting | The thread has been blocked by a call to Signal or Enter from one of the locking mechanisms, CriticalSection, Mutex, or Semaphore. |
| Suspended | It will not execute because of a call to the Suspend method. |
| Sleeping | It has been put to sleep by a call to the Sleep method. |
| NotRunning | The thread will be in this state prior to a call to Run or after the thread has finished running. |
Notes
The Main Thread
A Real Studio application runs in the so-called main thread which is the only one managing events from the outside and the graphical user interface (UI). However, this thread is not accessible via methods of the Thread class; it is managed internally. All other threads are accessible and share execution time among each other and the main thread.
The Thread Class
Thread class objects are used to execute code that needs to run independently of the user interface. The Thread Scheduler allocates processing cycles between the main thread and any threads you create via this class.
For example, if you were drawing a complex image that takes several minutes to render, this code could be executed in a thread so that the user could continue using the user interface without having to wait for the rendering to finish.
A thread can be used to allow a very time-consuming loop to run in the background. Since unthreaded loops take over the interface, preventing the user from making menu selections or interacting with a window's controls, this is a good way to allow the user to continue working with the application while a lengthy process is taking place.
| NOTE: Manipulating the UI from within a thread is not recommended and in fact is prohibited in newer versions as it can cause serious issues: application hangup, crashes... There are better and safer ways to achieve such goal. |
Threads can yield time to other threads and other applications each time they execute a looping construct such as For, While, and Do. However, a thread does not necessarily yield time at every loop boundary even though it has an opportunity to do so. A thread actually yields to another thread when the Thread Scheduler decides that its timeslice has expired. Context switches are expensive, so the Thread Scheduler always tries to avoid them.
To create a thread, create a new class and make Thread its super class. Add the new class to the Project. Put the code you wish to execute in the thread's Run event handler. To execute the thread, simply create a new instance of this object and call its Run method. You can do this by adding the instance of the Thread class to a window, as shown in the example, or instantiate it in the usual way.
Safely Sharing Resources Between Threads
As threads are running simultaneously, there can be problems if 2 or more threads are using the same data. For example, if several threads may need to access the same file, you can use a CriticalSection to be sure that two or more threads are not trying to access the same file simultaneously.
See the Semaphore, CriticalSection, and Mutex classes to see how to manage access to shared resources among multiple threads
How CPU Time is Shared Between Threads?
Threads are managed by Real Studio’s Thread Scheduler. Its task is to allocate the CPU’s processing cycles among all of the application’s threads. The Priority property determines how many or how few processing cycles the thread gets, relative to the main thread and any other threads that you have created.
Threads run in the background, but are temporarily blocked by certain user actions:
- While the mouse button is held down,
- While a window is being dragged,
- While a menu in the menu bar is pulled down,
- While the mouse button is pressed on a control in a window (not true of Windows)
When the Thread Scheduler decides to stop execution of the current thread and allow another thread to run, it is called a context switch. The amount of time a thread runs is called the time slice for the thread.
| NOTE: Using the DoEvents method of the Application class from a multithreaded application is not supported and will most likely generate extremely hard to track down errors and crashes in your application. See DoEvents for more information. |
Examples
To set up this example, first add a new class to the Project called LongProcessThread and set its Super class to Thread. In the Run event, place the following code:
Dim s as String
Const c = 186000
Const bigNum = 100000000
For i = 1 to bigNum
If i / 1000 = i \ 1000 then
//do something really tedious here...anything you want
s = Str(i/c*c*c) + " for " + Str(bigNum)
//just try to update the interface
Window1.ListBox1.AddRow s //add a row to the ListBox
End if
Next
MsgBox "Finished"
Add an instance of the LongProcessThread class to the default window, Window1. Add a ListBox, ListBox1, to the default window and a PushButton to the window with the following Action event handler:
This event handler does the calculations as a new thread. To see how the user-created thread makes a difference, create a second PushButton in the window and use the code in the Thread's Run event as the PushButton's Action event. When this button is clicked, Real Studio will do the same calculations, but in the main thread rather than in the thread you created.
When you do the calculation in its own thread, you will see that Real Studio is able to update the ListBox while the calculation is in progress and allows the user to manipulate interface items, such as scroll the ListBox and choose menu items. However, when you do the calculation inside the main thread, the interface is locked up until the calculation is finished.
Updating the Interface Using a Thread
The following example illustrates how to update an interface using a Timer and a Thread. The computation is done in the Thread but the interface is updated via the Timer in the main thread.
The user interface has a PushButton and a ProgressBar. A Timer and a Thread object are on the Window (see the following illustration).
The Action event of the PushButton gives the ProgressBar an ititial value and sets the mode of the Timer to Multiple. The Timer periodically checks on the status of the ProgressBar.
Timer1.Mode = Timer.ModeMultiple //periodically check ProgressBar and update the interface
Thread1.Run
The Run method of the Thread is what maintains the ProgressBar. ProgressValue is a property (Double) of the window.
while progressValue < 100 //if not the Maximum...
progressValue = progressValue + 1 //recompute progressValue
// do nothing for 1/4 second or so so folks can see the actual progress
dim waitUntil as integer = ticks + 15
while ticks < waitUntil
wend
wend
The Timer periodically checks the state of the ProgressBar. If it has not reached its maximum value, it updates it with the computed value.
ProgressBar1.value = ProgressBar1.Maximum
me.mode = timer.ModeOff //turns off the checking/updating
else //if not maximum
ProgressBar1.value = progressValue //updates the interface with the current value
end if
See Also
Application, DoEvents, CriticalSection, Mutex, Semaphore, Timer, WebTimer classes; #Pragma directives; ThreadAlreadyRunningException, ThreadEndException.
