Class
Thread
Description
Threads execute code in the background.
Properties
Name |
Type |
Read-Only |
Shared |
---|---|---|---|
Thread |
✓ |
✓ |
|
✓ |
|||
✓ |
|||
Methods
Name |
Parameters |
Returns |
Shared |
---|---|---|---|
data As Dictionary |
|||
ParamArray data As Pair |
|||
milliseconds As Integer |
✓ |
||
✓ |
Events
Name |
Parameters |
Returns |
---|---|---|
data() As Dictionary |
Constants
Priority
The following class constants can be used to set the priority of the thread with the Priority property.
Class Constant |
Value |
Description |
---|---|---|
LowestPriority |
1 |
Lowest priority |
NormalPriority |
5 |
Normal priority (same as Main thread) |
HighPriority |
10 |
High priority |
These values are totalled, then divided by the main thread and divvied out by proportion, but the main thread always has a priority of five, so using very large numbers for other threads will potentially starve the main thread. For example, if you give a second thread a priority of 500, there will be a total 505 slots in the scheduler and five of those belong to the main thread. Read more about priority below.
State
You can test the state of a thread by comparing the ThreadState property to the various ThreadStates.
Enumerations
Thread.Types
Types
The different types a Thread can be.
Enum |
Description |
---|---|
Cooperative |
The thread shares time with all other cooperative threads as well the app itself, all of which run on a single core of the CPU. |
Preemptive |
The thread can run on a core separate from other preemptive threads and the app itself. |
Thread.ThreadStates
ThreadStates
Specifies all possible states a Thread can be in.
Enum |
Description |
---|---|
Running |
The code is executing. |
Waiting |
The thread has been blocked by a call to Signal or Enter from one of the locking mechanisms, CriticalSection, Mutex, or Semaphore. |
Paused |
The code has halted because the Pause method was called. |
Sleeping |
The code has halted because the Sleep method was called. |
NotRunning |
The code is not running the Start method has not yet been called or the code has already finished running. |
Property descriptions
Thread.Current
Current As Thread
Returns the Thread that was executing at the moment this property was read.
This property is read-only.
Important
This property is not supported for Android.
This property is shared.
This property is Nil when accessed from the main Thread.
Thread.DebugIdentifier
DebugIdentifier As String
Identifier which will show up in the debugger's Thread popup.
Thread.Priority
Priority As Integer
Gets and sets the relative priority of the Thread.
Important
This property is not supported for Android.
The Priority can be changed while a Thread is running.
The application's main Thread has a priority of 5 and this is also the default value of any programmatically created threads. If you don't modify this value, your application will behave normally, in the sense that all the threads will share the CPU's resources equally.
Increasing the value of Priority above 5 gives that Thread more processing cycles than other threads. Doubling the value of Priority will double the number of processing cycles the Thread gets. A Thread with a Priority of 1 will get one-fifth the processing cycles as the main Thread. The range is 1 to 2^31-1, but very high values of Priority will make it difficult for other threads to run at all. The value of Priority changes the way in which threads get processing cycles only if their values are not all equal. You can use the following class constants to assign to Priority or to compare its value:
Value |
Description |
---|---|
1 |
LowestPriority |
5 |
NormalPriority |
10 |
HighPriority |
You do not need to use these constants; you can use any legal integer value instead.
This example lowers the priority of the Thread prior to calling its Start method.
Thread1.Priority = Thread.LowestPriority
Thread1.Start
Thread.StackSize
StackSize As Integer
The size of the stack, in bytes.
Important
This property is not supported for Android.
The StackSize can only be set when the Thread is not running. The default stack size is 512KB on macOS and Linux and 1MB on Windows. A StackSize of zero indicates the default is used.
There is generally little reason to change this. Each stack frame only need to contain information about the parameters, local variables and return address for a method call. This does not include memory needed for objects. It would take a significant amount of local variables or parameters with method calls that are 100s of levels deep in order to exhaust the stack space.
Thread1.StackSize = 96000
Thread.ThreadID
ThreadID As Integer
ID of the Thread, assigned at runtime.
This property is read-only.
Note: ThreadID will be non-zero only when the Thread is running.
This example reports the ThreadID only if the Thread is running.
If LongProcessThread1.State <> Thread.NotRunning Then
MessageBox(LongProcessThread1.ThreadID.ToString)
Else
MessageBox("The thread is not running!")
End If
Thread.ThreadState
ThreadState As ThreadStates
Indicates the state of the Thread.
This property is read-only.
A Thread can be in one of five states. See ThreadStates for details.
This window method checks the State of the Thread and displays a message in a TextField on the form. The parameter is:
State As Thread.ThreadStates
Select Case State
Case Thread.ThreadStates.Running
TextField1.Text = "Running"
Case Thread.ThreadStates.Waiting
TextField1.Text = "Waiting"
Case Thread.ThreadStates.Sleeping
TextField1.Text = "Sleeping"
Case Thread.ThreadStates.Paused
TextField1.Text = "Paused"
Case Thread.ThreadStates.NotRunning
TextField1.Text = "Not Running"
End Select
Thread.Type
Type As Types
Indicates the type of the Thread, Cooperative or preemptive. Cooperative is the default.
Carefully read the Preemptive Threads notes before using them.
Method descriptions
Thread.AddUserInterfaceUpdate
AddUserInterfaceUpdate(data As Dictionary)
AddUserInterfaceUpdate(ParamArray data As Pair)
Triggers the UserInterfaceUpdate event so you can update your user interface from the Thread.
Important
This method is not supported for Android.
Thread.Pause
Pause
Puts the Thread in a paused state. Every call to Pause must be matched by a call to Resume.
The Thread will not be allocated any processing cycles, regardless of its assigned Priority. It is “asleep.” To wake it up, call the Resume method. If the Thread is executing when you call Pause, it will immediately cause a context switch.
This example calls Pause, followed by a call to Resume after other code has executed.
LongProcessThread1.Pause
' do something else here...
LongProcessThread1.Resume
Thread.Resume
Resume
Wakes up a Thread that was paused because of a call to Thread.Pause or is sleeping because of a call to Thread.Sleep. Every call to Pause must be matched by a call to Resume.
When you call Resume, the Thread reacquires its ability to receive processing cycles according to its value of Priority. Calling Resume will not cause a context switch to take place, that is, a switch to the next Thread in the queue.
LongProcessThread1.Resume
Thread.Sleep
Sleep(milliSeconds As Integer, WakeEarly As Boolean = False)
Puts the Thread to sleep for the specified amount of time.
By default, wakeEarly is False. If it is not set to True, the Thread will be put to sleep for the full amount of time specified by milliSeconds. If you set wakeEarly to True, the Thread can be resumed early. It will wake up early if there are no other threads able to execute.
Calling this method when the Thread is already sleeping will result in the Thread instead sleeping for the milliseconds specified by the most recent call.
LongProcessThread1.Sleep(300, True)
Thread.SleepCurrent
SleepCurrent(milliseconds As Integer)
Sleeps the currently executing Thread for the specified number of milliseconds.
This method is shared.
If the currently executing Thread is the main Thread, it will sleep like any other Thread would.
Thread.Start
Start
Starts the Thread's Run event handler.
Thread.Stop
Stop
Stops the specified Thread.
Internally, this method will cause your Thread's stack to unwind, destructors for local objects to be called, and so forth. It's a graceful exit which can cause code to execute. It may also cause context switches.
Note
A Thread should not stop itself. Instead, just return from the Run event handler to allow the Thread to end.
This example, which is in the Pressed event of a button, stops the Thread.
LongProcessThread1.Stop
Thread.YieldToNext
YieldToNext
Causes the current Thread to yield its time to the next Thread.
This method is shared.
This causes the Thread Scheduler to yield the currently executing Thread's processing time to the next Thread in the queue that is awaiting processing cycles. It is possible for the next Thread to be the currently executing Thread.
Event descriptions
Thread.Run
Run
The Start method has been called. The threaded code is placed in this event handler. Methods called from here also run in the Thread.
MacOS apps cannot access the user interface from within a Thread. Doing so raises a ThreadAccessingUIException. Instead, use the AddUserInterfaceUpdate method in conjunction with the UserInterfaceUpdate event. See the UserInterfaceUpdate event for an example.
Thread.UserInterfaceUpdate
UserInterfaceUpdate(data() As Dictionary)
Used to update your app's user interface.
Important
This event is not supported for Android.
Apps cannot access the user interface from within the Run event of a Thread. Doing so raises a ThreadAccessingUIException. Instead, use the UserInterfaceUpdate event to update your user interface. It can be triggered by calling the AddUserInterfaceUpdate method from within the Run event.
Each call to AddUserInterfaceUpdate in the Run event, adds the values passed to an array that is then passed to the UserInterfaceUpdate event (the data() parameter above). This allows you to process all of the calls to AddUserInterfaceUpdate or just the most recent one. For example, if your Thread was reading a series of files and you wished to add the name of each file read to a ListBox, you'd want to read each row of the data() array passed to this event. However, if you instead were only displaying a ProgressBar and wanted to show how far you'd gotten through reading all the files, it would be more efficient to read the last item of the data() array passed to this event and then update your ProgressBar control rather than iterate through all of the items in the data() array.
This code (in the UserInterfaceUpdate event) updates a ProgressBar (called UIProgress) on a Window:
For Each update As Dictionary In data
If update.HasKey("UIProgress") Then
UIProgress.Value = update.Value("UIProgress").IntegerValue
End If
Next
The Data parameter is an array of Dictionaries containing information supplied by the AddUserInterfaceUpdate method that can be used to update the UI.
The Run event contains the code that runs in the Thread and calls AddUserInterfaceUpdate with any necessary information:
Var progressValue As Integer
While progressValue < 100
progressValue = progressValue + 1
//Your processing code goes here. For the sake of this example
//we've added a dummy loop below so you can see the progress bar update.
' Do nothing for 1/4 second
Var waitUntil As Integer = System.Ticks + 15
While System.Ticks < waitUntil
Wend
' Call AddUserInterfaceUpdate with any parameters you need. This calls the UserInterfaceUpdate event handler
' where you can directly access any UI controls on the Window.
' This specifies simple parameters using a Pair
' You can also pass values using a Dictionary
Me.AddUserInterfaceUpdate("UIProgress" : progressValue)
Wend
Notes
Threads stay in scope as long as they are active, even if the variable or property referring to the Thread goes out of scope.
Updating the user interface from a thread
Warning
Do not access any built-in property or method of a user interface control or Window from a Thread's Run event or any methods called from it as platform UI frameworks (macOS, Windows and Linux) are not Thread-safe. Doing so raises a ThreadAccessingUIException. See below for additional information.
Your application code normally runs in the so-called main Thread which is the Thread responsible for managing events in the user interface. If you have a long-running process that runs in the main Thread, the user interface will not update and will be unresponsive to the user.
Typically, you use the Thread class to run code that will not affect the state of the user interface. This also means that code that runs in these threads cannot access the user interface. Doing so raises a ThreadAccessingUIException.
Essentially, a Thread is used to allow a very time-consuming process to run in the background. There may be times where you want to update the user interface with something that has been processed in the Thread. The way to do this is by putting the code that updates your user interface in the UserInterfaceUpdate event and triggering it from the Run event by calling the AddUserInterfaceUpdate method inside the loop you likely have running in your Run event handler.
Keep in mind that a Thread can access your own properties and methods that are part of UI controls or Windows as long as they do not in turn access your app's user interface controls.
Safely sharing resources between threads
Sometimes you may have a resource (data or a file, for example) that needs to be used by multiple threads that are all currently running. An example would be that a Thread tries to open a file for writing that another Thread has already opened for writing. This can cause issues and unwanted exceptions.
You can manage this by using a CriticalSection, Semaphore or Mutex to prevent multiple threads from trying to access the same shared resource.
Preemptive threads
Threads, by default, are cooperative. This means that they all run on the same core of the CPU along with the app itself. Therefore they share that resource which means the more processing that core is doing, the longer a cooperative thread will take to complete. Preemptive threads can run on a core of the CPU separate from other preemptive threads and separate from the app itself. If a core is available, a preemptive thread will run on it. Otherwise, it will be run on a core that is also handling other tasks. Thus the advantage of a preemptive thread is that it can execute potentially far faster than a cooperative thread.
To create a preemptive thread, set the Type property to Preemptive. You can change the type of a Thread at runtime but only from within the Thread itself.
Because preemptive threads can execute on any available core, they do not share memory with each other nor with your app as cooperative threads do. This means the code in the thread will have no access to the values of any other objects in your app.
A lot of the ways in which Xojo protects you (for example, from writing code that will crash your app) are not available to preemptive threads. Thus extra care must be taken when using them.
Operating systems are not designed to allow access to the graphical user interface components (window, controls, menus, etc.) from preemptive threads. Doing so will likely cause your application to crash. Xojo's Runtime.IterateObjects method and XojoScript are not safe to use in a preemptive thread.
Be aware that stack overflow checks are not performed on preemptive threads. If the thread's stack overflows, your app will crash.
Do not switch thread types within a Semaphore lock or CriticalSection. Doing so will result in the app crashing or becoming locked up.
When adding or removing items from arrays or dictionaries, use a Semaphore and/or CriticalSection to ensure that a preemptive thread is not modifying the object at the same moment as another thread.
When used with a preemptive thread, the Type property of a Semaphore or CriticalSection must also be set to Preemptive. Failing to do this will result in an IllegalLockingException.
Important
Preemptive threads are not currently supported on Android.
Android
The Thread class has limitations with Android. You cannot pause and resume threads and all threads run at the same priority. Preemptive threads are not yet supported for Android.
Compatibility
All project types on all supported operating systems.
See also
Object parent class; DesktopApplication, CriticalSection, Mutex, Semaphore, Timer, WebTimer classes; Pragma directives; ThreadAlreadyRunningException, ThreadEndException, ThreadAccessingUIException.