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.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
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.
Android
The Thread class has limitations with Android. You cannot pause and resume threads and all threads run at the same priority.
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.