Class

Thread


Description

Threads execute code in the background.

Properties

Name

Type

Read-Only

Shared

Current

Thread

DebugIdentifier

String

Priority

Integer

StackSize

Integer

ThreadID

Integer

ThreadState

ThreadStates

Methods

Name

Parameters

Returns

Shared

AddUserInterfaceUpdate

data As Dictionary

ParamArray data As Pair

Pause

Resume

Sleep

milliSeconds As Integer, wakeEarly As Boolean = False

SleepCurrent

milliseconds As Integer

Start

Stop

YieldToNext

Events

Name

Parameters

Returns

Run

UserInterfaceUpdate

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.


How cpu time is shared between threads

Threads are managed by the built-in Thread Scheduler. Its task is to allocate the CPU's processing cycles among all of the application's threads. Note that because Threads are cooperative, they all share the CPU cycles of a single CPU core. Threads cannot access other CPU cores. The Priority property determines how many or how few processing cycles the Thread gets, relative to the main Thread (which always has a priority of 5) and any other Threads that you have created. Use a higher value for Priority to give a Thread more CPU cycles and a lower value to give it less CPU cycles.

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.

Threads can yield time to other threads and other applications each time they execute a looping construct such as For, While, and Do...Loop. 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.

You can also force context switches by calling YieldToNext or by calling SleepCurrent.

Note

Code that runs in threads does not run faster (in fact such code typically runs more slowly because the CPU time is shared as described above). Putting code in a Thread is a way to provide a better user experience by allowing tasks to be perceived as running in the background.

Compatibility

All project types on all supported operating systems.