Was this page helpful?
Your feedback about this content is important. Let us know what you think.
Additional feedback?
1500 characters remaining
Creating Threads and Passing Data at Start Time

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.


using System;
using System.Threading;

public class Example
{
   private static System.Windows.Controls.TextBlock outputBlock;

   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      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. C# expands the method name to the appropriate 
      // delegate creation syntax:
      //    New ThreadStart(Example.DoWork)
      //
      Thread newThread = new Thread(Example.DoWork);
      newThread.Start();
   }

   // 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 static void DoWork()
   {
      outputBlock.Dispatcher.BeginInvoke(delegate () { 
         outputBlock.Text += "Hello from a static thread procedure.\n"; 
      });
   }
}

/* This code example produces the following output:

Hello from a static 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.


using System;
using System.Threading;

public class Example
{
   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      // 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. C# expands the object
      // reference and method name to the appropriate delegate 
      // creation syntax:
      //    New ThreadStart(AddressOf w.DoMoreWork)
      //
      Work w = new Work();
      w.Data = 42;
      w.Output = outputBlock;

      Thread newThread = new Thread(w.DoMoreWork);
      newThread.Start();
   }
}

public class Work
{
   public int Data;
   public System.Windows.Controls.TextBlock Output;

   // 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 void DoMoreWork()
   {
      Output.Dispatcher.BeginInvoke(delegate () {
         Output.Text += String.Format("Instance thread procedure. Data={0}\n", Data);
      });
   }
}

// 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.


using System;
using 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 string boilerplate;
    private int value;

    public bool Finished = false;
    public string Result = null;

    // The constructor obtains the state information.
    public ThreadWithState(string text, int number)
    {
        boilerplate = text;
        value = number;
    }

    // The thread procedure performs the task, such as formatting 
    // and printing a document.
    public void ThreadProc()
    {
        Thread.Sleep(3000);
        Result = String.Format(boilerplate, value);
        Finished = true;
    }
}

// Entry point for the example.
//
public class Example
{
    private static System.Windows.Controls.TextBlock outputBlock;
    private static ThreadWithState tws;

    public static void Demo(System.Windows.Controls.TextBlock outputBlock)
    {
        Example.outputBlock = outputBlock;
        outputBlock.Text = "Click here to start the thread.\n";

        outputBlock.MouseLeftButtonUp += MouseUpStart;
    }

    private static void MouseUpStart(object sender, 
                                     System.Windows.Input.MouseButtonEventArgs e)
    {
        outputBlock.MouseLeftButtonUp -= 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.
        Thread t = new Thread(tws.ThreadProc);
        t.Start();

        outputBlock.Text = "Click here to check for the result.\n";
        outputBlock.MouseLeftButtonUp += MouseUp;
    }

    private static void MouseUp(object sender, 
                                System.Windows.Input.MouseButtonEventArgs e)
    {

        if (tws.Finished)
        {
            outputBlock.MouseLeftButtonUp -= MouseUp;
            outputBlock.Text += tws.Result + "\n";
        }
        else
        {
            outputBlock.Text += "Not done yet.\n";
        }
    }
}


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.


using System;
using 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 string boilerplate;
    private int number;
    private Action<string> callback;

    // The constructor obtains the state information and the
    // callback delegate.
    public ThreadWithState(string boilerplate, int number, Action<string> callback)
    {
        this.boilerplate = boilerplate;
        this.number = number;
        this.callback = callback;
    }

    // The thread procedure performs the task, and then makes a cross-
    // thread call to return the result.
    public void ThreadProc()
    {
        Thread.Sleep(3000);
        string result = String.Format(boilerplate, number);
        if (callback != null) { callback(result); }
    }
}

// Entry point for the example.
//
public class Example
{
    private static System.Windows.Controls.TextBlock outputBlock;

    public static void Demo(System.Windows.Controls.TextBlock outputBlock)
    {
        Example.outputBlock = outputBlock;

        // Supply the state information required by the task.
        ThreadWithState tws = 
           new ThreadWithState("This report displays the number {0}.\n", 
                               42, ResultCallback);

        Thread t = new Thread(tws.ThreadProc);
        t.Start();
        outputBlock.Text += "Thread started.\n";

        outputBlock.MouseLeftButtonUp += MouseUp;
    }

    // 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. 
    //
    internal static void ResultCallback(string msg)
    {
        outputBlock.Dispatcher.BeginInvoke(displayHelper, msg);
    }

    private static Action<string> displayHelper = new Action<string>(DisplayOutput);
    private static void DisplayOutput(string msg)
    {
        outputBlock.Text += msg;
    }

    // Show that the user interface remains responsive.
    private static void MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        outputBlock.Text += "Mouse Up.\n";
    }
}


Community Additions

ADD
Show:
© 2015 Microsoft