Creating Threads and Passing Data at Start Time
Collapse the table of content
Expand the table of content

Creating Threads and Passing Data at Start Time

When a Silverlight-based application starts, the currently executing thread is the user interface thread. You can determine the thread that is executing code at any given time by retrieving the static Thread.CurrentThread property (Shared property in Visual Basic). This topic describes the creation of additional threads, and discusses alternatives for passing data to the thread procedure.

Creating a new Thread object creates a new managed thread. The Thread class has constructors that take a ThreadStart delegate or a ParameterizedThreadStart delegate; the delegate wraps the method that is invoked by the new thread when you call the Start method. Calling Start more than once causes a ThreadStateException to be thrown.

The Start method returns immediately, often before the new thread has actually started. You can use the ThreadState and IsAlive properties to determine the state of the thread at any one moment, but these properties should never be used for synchronizing the activities of threads.

Note Note:

Once a thread is started, it is not necessary to retain a reference to the Thread object. The thread continues to execute until the thread procedure ends.

The following example shows how to execute a static method on a new thread. To run this example, see Building Examples That Use a Demo Method and a TextBlock Control.


Imports System.Threading

Public Class Example

   Private Shared outputBlock As System.Windows.Controls.TextBlock

   Public Shared Sub Demo(ByVal outputBlock As System.Windows.Controls.TextBlock)

      Example.outputBlock = outputBlock

      ' To start a thread using a static thread procedure, use the
      ' class name and method name when you create the ThreadStart
      ' delegate. Visual Basic expands the AddressOf expression 
      ' to the appropriate delegate creation syntax:
      '    New ThreadStart(AddressOf Example.DoWork)
      '
      Dim newThread As New Thread(AddressOf Example.DoWork)
      newThread.Start()

   End Sub

   ' Simulate work. To communicate with objects on the UI thread, get the 
   ' Dispatcher for one of the UI objects. Use the Dispatcher object's 
   ' BeginInvoke method to queue a delegate that will run on the UI thread,
   ' and therefore can safely access UI elements like the TextBlock.
   Private Shared Sub DoWork()
      Dim display As New Action(Of String)(AddressOf DisplayOutput)

      outputBlock.Dispatcher.BeginInvoke(display, _
         "Hello from a Shared thread procedure." & vbCrLf)
   End Sub

   ' The Dispatcher.BeginInvoke method runs this helper method on the 
   ' UI thread, so it can safely access the TextBlock that is used to 
   ' display the output.
   Private Shared Sub DisplayOutput(msg)
      outputBlock.Text &= msg
   End Sub

End Class

' This code example produces the following output:
'
'Hello from a Shared thread procedure.


The following example shows how to execute an instance method on a new thread. To run this example, see Building Examples That Use a Demo Method and a TextBlock Control.


Imports System.Threading

Public Class Example

   Public Shared Sub Demo(ByVal outputBlock As System.Windows.Controls.TextBlock)

      ' To start a thread using an instance method for the thread 
      ' procedure, use the instance variable and method name when 
      ' you create the ThreadStart delegate. Visual Basic expands 
      ' the AddressOf expression to the appropriate delegate 
      ' creation syntax:
      '    New ThreadStart(AddressOf w.DoMoreWork)
      '
      Dim w As New Work()
      w.Data = 42
      w.Output = outputBlock

      Dim newThread As Thread = New Thread(AddressOf w.DoMoreWork)
      newThread.Start()
   End Sub

End Class

Public Class Work
   Public Data As Integer
   Public Output As System.Windows.Controls.TextBlock

   ' Simulate work. To communicate with objects on the UI thread, get the 
   ' Dispatcher for one of the UI objects. Use the Dispatcher object's 
   ' BeginInvoke method to queue a delegate that will run on the UI thread,
   ' and therefore can safely access UI elements like the TextBlock.
   Public Sub DoMoreWork()
      Dim display As New Action(Of String)(AddressOf DisplayOutput)

      Output.Dispatcher.BeginInvoke(display, _
         String.Format("Instance thread procedure. Data={0}", Data) & vbCrLf)
   End Sub

   ' The Dispatcher.BeginInvoke method runs this helper method on the 
   ' UI thread, so it can safely access the TextBlock that is used to 
   ' display the output.
   Private Sub DisplayOutput(msg)
      Output.Text &= msg
   End Sub

End Class

' This code example produces the following output:
'
'Instance thread procedure. Data=42


If you are running background tasks from the user interface thread, the BackgroundWorker class provides a simple, event-driven model for communicating between the background thread and the user interface thread. See How to: Use a Background Worker.

The ParameterizedThreadStart delegate provides an easy way to pass an object that contains data to a thread: Simply pass the object to the Start(Object) method overload. See ParameterizedThreadStart for a code example.

Using the ParameterizedThreadStart delegate is not a type-safe way to pass data, because the Start(Object) method overload accepts any object. An alternative is to encapsulate the thread procedure and the data in a helper class and use the ThreadStart delegate to execute the thread procedure. This technique is shown in the two examples in the following sections.

The ThreadStart and ParameterizedThreadStart delegates do not have return values, because there is no place to return the data from an asynchronous call. To retrieve the results of a thread method, you can get the data from the object that encapsulates the data, as shown in the example in the Retrieving Data by Polling section, or allow the thread to call back with the results. In a Silverlight-based application this might mean making a cross-thread callback to the user interface thread, as shown in the second example, in the Retrieving Data with Callback Methods section.

Important note Important Note:

In Silverlight-based applications, avoid making blocking calls in code that runs on the user interface thread. If the user interface thread waits for another thread by calling Join or other methods that block, your application becomes unresponsive.

Retrieving Data by Polling

The following example defines a ThreadWithState class that contains both the data and the thread procedure. The result of the thread procedure is stored in an internal field (Friend field in Visual Basic) where it can be retrieved by code that is running on the user interface thread. In this example, the user interface code that polls for the result is in a mouse button event.

To run this example, see Building Examples That Use a Demo Method and a TextBlock Control.


Imports System.Threading

' The ThreadWithState class contains the information needed for
' a task, and the method that executes the task.
'
Public Class ThreadWithState
    ' State information used in the task.
    Private boilerplate As String
    Private value As Integer

    Public Finished As Boolean = False
    Public Result As String = Nothing

    ' The constructor obtains the state information.
    Public Sub New(ByVal text As String, ByVal number As Integer)
        boilerplate = text
        value = number
    End Sub

    ' The thread procedure performs the task, such as formatting 
    ' and printing a document.
    Public Sub ThreadProc()
        Thread.Sleep(3000)
        Result = String.Format(boilerplate, value) 
        Finished = True
    End Sub


End Class

' Entry point for the example.
'
Public Class Example

    Private Shared outputBlock As System.Windows.Controls.TextBlock
    Private Shared tws As ThreadWithState

    Public Shared Sub Demo(ByVal outputBlock As System.Windows.Controls.TextBlock)

        Example.outputBlock = outputBlock
        outputBlock.Text = "Click here to start the thread." & vbLf 

        AddHandler outputBlock.MouseLeftButtonUp, AddressOf MouseUpStart

    End Sub

    Private Shared Sub MouseUpStart(ByVal sender As Object, _
                                    ByVal e As MouseButtonEventArgs)

        RemoveHandler outputBlock.MouseLeftButtonUp, AddressOf MouseUpStart

        ' Supply the state information required by the task.
        tws = New ThreadWithState("This report displays the number {0}.", 42)

        ' Create a thread to execute the task, and then
        ' start the thread.
        Dim t As New Thread(AddressOf tws.ThreadProc)
        t.Start()

        outputBlock.Text = "Click here to check for the result." & vbLf
        AddHandler outputBlock.MouseLeftButtonUp, AddressOf MouseUp

    End Sub

    Private Shared Sub MouseUp(ByVal sender As Object, _
                               ByVal e As MouseButtonEventArgs)

        If tws.Finished Then
            RemoveHandler outputBlock.MouseLeftButtonUp, AddressOf MouseUp
            outputBlock.Text &= tws.Result
        Else
            outputBlock.Text &= "Not done yet." & vbLf
        End If

    End Sub
End Class


Retrieving Data with Callback Methods

The following example demonstrates a callback method that returns data from a thread. The constructor for the class that contains the data and the thread method also accepts a delegate representing the callback method; before the thread method ends, it invokes the callback delegate.

To run this example, see Building Examples That Use a Demo Method and a TextBlock Control.


Imports System.Threading

' The ThreadWithState class contains the information needed for
' a task, the method that executes the task, and a delegate
' to call when the task is complete.
'
Public Class ThreadWithState
    ' State information used in the task.
    Private boilerplate As String
    Private number As Integer
    Private callback As Action(Of String)

    ' The constructor obtains the state information and the
    ' callback delegate.
    Public Sub New(ByVal boilerplate As String, ByVal number As Integer, _
                   ByVal callback As Action(Of String))
        Me.boilerplate = boilerplate 
        Me.number = number
        Me.callback = callback
    End Sub

    ' The thread procedure performs the task, and then makes a cross-
    ' thread call to return the result.
    Public Sub ThreadProc()
        Thread.Sleep(3000)
        Dim result As String = String.Format(boilerplate, number) 
        If Not callback Is Nothing Then callback(result)
    End Sub

End Class

' Entry point for the example.
'
Public Class Example

    Private Shared outputBlock As System.Windows.Controls.TextBlock
    Private Shared tws As ThreadWithState

    Public Shared Sub Demo(ByVal outputBlock As System.Windows.Controls.TextBlock)

        Example.outputBlock = outputBlock

        ' Supply the state information required by the task.
        Dim tws As New ThreadWithState("This report displays the number {0}." & vbLf, _
                                       42, AddressOf ResultCallback)

        Dim t As New Thread(AddressOf tws.ThreadProc)
        t.Start()
        outputBlock.Text &= "Thread started." & vbLf

        AddHandler outputBlock.MouseLeftButtonUp, AddressOf MouseUp

    End Sub

    ' In order to update the TextBlock object, which is on the UI thread, 
    ' a cross-thread call must use the Dispatcher object that is associated 
    ' with the TextBlock. The DisplayOutput helper method and its delegate, 
    ' displayHelper, are used by the BeginInvoke method of the Dispatcher 
    ' object to append text to the TextBlock. 
    '
    Friend Shared Sub ResultCallback(ByVal msg As String)
        outputBlock.Dispatcher.BeginInvoke(displayHelper, msg)
    End Sub

    Private Shared displayHelper As New Action(Of String)(AddressOf DisplayOutput)
    Private Shared Sub DisplayOutput(ByVal msg As String)
        outputBlock.Text &= msg 
    End Sub

    ' Show that the user interface remains responsive.
    Private Shared Sub MouseUp(ByVal sender As Object, _
                               ByVal e As MouseButtonEventArgs)
        outputBlock.Text &= "Mouse Up." & vbLf
    End Sub

End Class


Community Additions

ADD
Show:
© 2016 Microsoft