Creating Threads

When an operating-system process is created, the operating system injects a thread to execute code in that process, including any original application domain. From that point on, application domains can be created and destroyed without any operating system threads necessarily being created or destroyed. If the code being executed is managed code, then a Thread object for the thread executing in the current application domain can be obtained by retrieving the static property on the thread class Thread.CurrentThread.

Creating a new instance of a Thread object creates new managed threads. As its only parameter, the constructor for Thread takes a ThreadStart delegate that wraps the method that will be invoked by the new Thread when you call Thread.Start. Calling Thread.Start more than once will cause a ThreadStateException to be thrown.

Thread.Start submits an asynchronous request to the system, and the call returns immediately, possibly before the new thread has actually started. You can use Thread.ThreadState and Thread.IsAlive to determine the state of the thread at any one moment. Thread.Abort aborts a thread, marking it for garbage collection. The following code example creates two new threads to call instance and static methods on another object.

Imports System
Imports System.Threading

Public Class ServerClass
   
   ' The method that will be called when the thread is started.
   Public Sub InstanceMethod()
      Console.WriteLine("ServerClass.InstanceMethod is running on another thread.")
      Thread.Sleep(3000) ' Pause for a moment to provide a delay to make threads more apparent.
      Console.WriteLine("The instance method called by the worker thread has ended.")
   End Sub 'InstanceMethod
   
   Public Shared Sub StaticMethod()
      Console.WriteLine("ServerClass.StaticMethod is running on another thread.")
      Thread.Sleep(5000) ' Pause for a moment to provide a delay to make threads more apparent.
      Console.WriteLine("The static method called by the worker thread has ended.")
   End Sub 'StaticMethod
End Class 'ServerClass

Public Class Simple
   
   Public Shared Sub Main() 
      Console.WriteLine("Thread Simple Sample")
      
      Dim serverObject As New ServerClass()
      
      ' Create the thread object, passing in the 
      ' serverObject.InstanceMethod method using a
      ' ThreadStart delegate.
      Dim InstanceCaller As New Thread(New ThreadStart(AddressOf serverObject.InstanceMethod))
      
      ' Start the thread.
      InstanceCaller.Start()
      
      Console.WriteLine("The Main() thread calls this after starting the new InstanceCaller thread.")
      
      ' Create the thread object, passing in the serverObject.StaticMethod 
      ' method using a ThreadStart delegate.
      Dim StaticCaller As New Thread(New ThreadStart(AddressOf ServerClass.StaticMethod))
      
      ' Start the thread.
      StaticCaller.Start()
      
      Console.WriteLine("The Main() thread calls this after starting the new StaticCaller threads.")
      
   End Sub 'Main
End Class 'Simple
[C#]using System;
using System.Threading;

public class ServerClass{
   // The method that will be called when the thread is started.
   public void InstanceMethod(){
      Console.WriteLine("ServerClass.InstanceMethod is running on another thread.");
      // Pause for a moment to provide a delay to make threads more apparent.
      Thread.Sleep(3000);
      Console.WriteLine("The instance method called by the worker thread has ended.");
   }

   public static void StaticMethod(){
      Console.WriteLine("ServerClass.StaticMethod is running on another thread.");
      // Pause for a moment to provide a delay to make threads more apparent.
      Thread.Sleep(5000);
      Console.WriteLine("The static method called by the worker thread has ended.");
   }
}

public class Simple{
   public static int Main(String[] args){
      Console.WriteLine("Thread Simple Sample");

      ServerClass serverObject = new ServerClass();

      // Create the thread object, passing in the 
      // serverObject.InstanceMethod method using a ThreadStart delegate.
      Thread InstanceCaller = new Thread(new ThreadStart(serverObject.InstanceMethod));

      // Start the thread.
      InstanceCaller.Start();

      Console.WriteLine("The Main() thread calls this after starting the new InstanceCaller thread.");

      // Create the thread object, passing in the 
      // serverObject.StaticMethod method using a ThreadStart delegate.
      Thread StaticCaller = new Thread(new ThreadStart(ServerClass.StaticMethod));

      // Start the thread.
      StaticCaller.Start();

      Console.WriteLine("The Main() thread calls this after starting the new StaticCaller threads.");

      return 0;
   }
}

Passing Data To Threads

The ThreadStart delegate has no parameters or return value. This means that you cannot start a thread using a method that takes parameters, or obtain a return value from the method.

  • To pass data to a thread, create an object to hold the data and the thread method, as shown in the two code examples that follow.
  • To retrieve the results of a thread method, you can use a callback method, as demonstrated in the second code example.
Imports System
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

    ' 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()
        Console.WriteLine(boilerplate, value) 
    End Sub
End Class

' Entry point for the example.
'
Public Class Example
    Public Shared Sub Main()
        ' Supply the state information required by the task.
        Dim tws As 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()
        Console.WriteLine("Main thread does some work, then waits.")
        t.Join()
        Console.WriteLine("Independent task has completed; main thread ends.")  
    End Sub
End Class
[C#]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;

    // 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() {
        Console.WriteLine(boilerplate, value); 
    }
}

// Entry point for the example.
//
public class Example {
    public static void Main() {
        // Supply the state information required by the task.
        ThreadWithState 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(new ThreadStart(tws.ThreadProc));
        t.Start();
        Console.WriteLine("Main thread does some work, then waits.");
        t.Join();
        Console.WriteLine("Independent task has completed; main thread ends.");  
    }
}

Retrieving Data With Callback Methods

The following example demonstrates a callback method that retrieves 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.

Imports System
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 value As Integer
    ' Delegate used to execute the callback method when the
    ' task is complete.
    Private callback As ExampleCallback

    ' The constructor obtains the state information and the
    ' callback delegate.
    Public Sub New(ByVal text As String, ByVal number As Integer, _
                   ByVal callbackDelegate As ExampleCallback)
        boilerplate = text
        value = number
        callback = callbackDelegate
    End Sub
    
    ' The thread procedure performs the task, such as
    ' formatting and printing a document, and then invokes
    ' the callback delegate with the number of lines printed.
    Public Sub ThreadProc()
        Console.WriteLine(boilerplate, value) 
        If Not callback Is Nothing Then callback(1)
    End Sub
End Class

' Delegate that defines the signature for the callback method.
'
Public Delegate Sub ExampleCallback(ByVal lineCount As Integer)

' Entry point for the example.
'
Public Class Example
    Public Shared Sub Main()
        ' Supply the state information required by the task.
        Dim tws As New ThreadWithState( _
            "This report displays the number {0}.", _
            42, _
            New ExampleCallback(AddressOf ResultCallback) _
        )

        Dim t As New Thread(AddressOf tws.ThreadProc)
        t.Start()
        Console.WriteLine("Main thread does some work, then waits.")
        t.Join()
        Console.WriteLine("Independent task has completed; main thread ends.")  
    End Sub

    ' The callback method must match the signature of the
    ' callback delegate.
    '
    Public Shared Sub ResultCallback(ByVal lineCount As Integer)
        Console.WriteLine("Independent task printed {0} lines.", lineCount)  
    End Sub
End Class
[C#]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 value;
    // Delegate used to execute the callback method when the
    // task is complete.
    private ExampleCallback callback;

    // The constructor obtains the state information and the
    // callback delegate.
    public ThreadWithState(string text, int number, 
                   ExampleCallback callbackDelegate) 
    {
        boilerplate = text;
        value = number;
        callback = callbackDelegate;
    }
    
    // The thread procedure performs the task, such as
    // formatting and printing a document, and then invokes
    // the callback delegate with the number of lines printed.
    public void ThreadProc() {
        Console.WriteLine(boilerplate, value);
        if (callback != null)
            callback(1);
    }
}

// Delegate that defines the signature for the callback method.
//
public delegate void ExampleCallback(int lineCount);

// Entry point for the example.
//
public class Example {
    public static void Main() {
        // Supply the state information required by the task.
        ThreadWithState tws = new ThreadWithState(
            "This report displays the number {0}.",
            42,
            new ExampleCallback(ResultCallback)
        );

        Thread t = new Thread(new ThreadStart(tws.ThreadProc));
        t.Start();
        Console.WriteLine("Main thread does some work, then waits.");
        t.Join();
        Console.WriteLine("Independent task has completed; main thread ends."); 
    }

    // The callback method must match the signature of the
    // callback delegate.
    //
    public static void ResultCallback(int lineCount) {
        Console.WriteLine("Independent task printed {0} lines.", lineCount);  
    }
}

See Also

Threading | Using Threads and Threading