Crear subprocesos y analizar los datos en el inicio

Al crear un proceso del sistema operativo, éste introduce un subproceso para ejecutar el código de dicho proceso, incluido cualquier dominio de aplicación original. A partir de ese punto, pueden crearse y destruirse dominios de aplicación sin que necesariamente se cree o destruya ningún subproceso del sistema operativo. Si el código que se ejecuta es administrado, puede obtenerse un objeto Thread para el subproceso que se ejecuta en el dominio de aplicación actual si se recupera la propiedad estática CurrentThread de tipo Thread. En este tema se describe la creación de subprocesos y se analizan las alternativas para pasar datos al procedimiento de subproceso.

Crear un subproceso

Al crear un nuevo objeto Thread se crea un nuevo subproceso administrado. La clase Thread dispone de constructores que toman un delegado ThreadStart o ParameterizedThreadStart; el delegado contiene el método al que invoca el nuevo subproceso cuando se llama al método Start. Si se llama a Start más de una vez, se produce una excepción ThreadStateException.

Cuando el método Start devuelve el resultado, el subproceso se encuentra en el estado Running. Se puede programar su ejecución, pero quizás no haya empezado a ejecutarse.

NotaNota

En la mayoría de los casos, no es necesario asegurarse de que el nuevo subproceso haya empezado a ejecutarse antes de que el subproceso que lo inició continúe ejecutándose.Si es necesario, el subproceso que llamó al método Start debe bloquearse (por ejemplo, llamando al método Mutex.WaitOne en una exclusión mutua que está visible para el nuevo subproceso) en cuanto se haya iniciado el nuevo subproceso.El nuevo subproceso puede desbloquear el antiguo subproceso (por ejemplo, llamando al método Mutex.ReleaseMutex en la exclusión mutua compartida) en cuanto sea seguro que el antiguo subproceso continúe.No use las propiedades ThreadState y IsAlive para sincronizar las actividades de los subprocesos.

Una vez iniciado un subproceso, no es necesario conservar una referencia al objeto Thread. El subproceso se continúa ejecutando hasta que el procedimiento del mismo finaliza.

En el ejemplo de código siguiente se crean dos subprocesos nuevos para llamar a métodos estáticos y una instancia de otro objeto.

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.")

        ' 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.")
    End Sub

    Public Shared Sub SharedMethod()
        Console.WriteLine(
            "ServerClass.SharedMethod is running on another thread.")

        ' Pause for a moment to provide a delay to make
        ' threads more apparent.
        Thread.Sleep(5000)
        Console.WriteLine(
            "The Shared method called by the worker thread has ended.")
    End Sub
End Class

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.SharedMethod method using a
        ' ThreadStart delegate.
        Dim SharedCaller As New Thread( _
            New ThreadStart(AddressOf ServerClass.SharedMethod))

        ' Start the thread.
        SharedCaller.Start()

        Console.WriteLine("The Main() thread calls this after " _
            + "starting the new SharedCaller thread.")
    End Sub
End Class
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 void Main()
    {
        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 thread.");
    }
}
using namespace System;
using namespace System::Threading;

public ref class ServerClass
{
public:
    // The method that will be called when the thread is started.
    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.");
    }

    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 ref class Simple
{
public:
    static void Main()
    {
        Console::WriteLine("Thread Simple Sample");

        ServerClass^ serverObject = gcnew ServerClass();

        // Create the thread object, passing in the
        // serverObject.InstanceMethod method using a
        // ThreadStart delegate.
        Thread^ InstanceCaller = gcnew Thread(
            gcnew ThreadStart(serverObject, &ServerClass::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 = gcnew Thread(
            gcnew ThreadStart(&ServerClass::StaticMethod));

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

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

int main()
{
    Simple::Main();
}

Pasar datos a subprocesos y recuperar datos de subprocesos

En la versión 2.0 de .NET Framework, el delegado ParameterizedThreadStart proporciona una forma sencilla de pasar un objeto que contiene datos a un subproceso cuando se llama a la sobrecarga del método Thread.Start. Vea ParameterizedThreadStart para obtener un ejemplo de código.

El uso del delegado ParameterizedThreadStart no constituye un modo con seguridad de tipos para pasar los datos, dado que la sobrecarga del método Thread.Start acepta cualquier objeto. Una alternativa consiste en encapsular el procedimiento de subproceso y los datos en una clase auxiliar y utilizar el delegado ThreadStart para ejecutar el procedimiento de subproceso. Esta técnica se muestra en los dos ejemplos de código siguientes.

Ninguno de estos delegados presenta un valor devuelto, porque no hay ningún lugar donde devolver los datos de una llamada asincrónica. Para recuperar los resultados de un método de subproceso, puede utilizar un método de respuesta, como se muestra en el segundo ejemplo de código.

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(text As String, 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 {0End.", 42)

        ' Create a thread to execute the task, and then
        ' start the thread.
        Dim t As New Thread(New ThreadStart(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
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.");
    }
}
using namespace System;
using namespace System::Threading;

// The ThreadWithState class contains the information needed for
// a task, and the method that executes the task.
//
public ref class ThreadWithState
{
private:
    // State information used in the task.
    String^ boilerplate;
    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.
    void ThreadProc()
    {
        Console::WriteLine(boilerplate, value);
    }
};

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

        // Create a thread to execute the task, and then
        // start the thread.
        Thread^ t = gcnew Thread(gcnew ThreadStart(tws, &ThreadWithState::ThreadProc));
        t->Start();
        Console::WriteLine("Main thread does some work, then waits.");
        t->Join();
        Console::WriteLine(
            "Independent task has completed; main thread ends.");
    }
};

int main()
{
    Example::Main();
}

Recuperar datos con métodos de devolución de llamada

En el siguiente ejemplo se muestra un método de respuesta que recupera datos de un subproceso. El constructor de la clase que contiene los datos y el método del subproceso también acepta un delegado que representa el método de devolución de llamada; antes de finalizar, el método del subproceso invoca al delegado de devolución de llamada.

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(text As String, number As Integer, _
        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 If
    End Sub
End Class

' Delegate that defines the signature for the callback method.
'
Public Delegate Sub ExampleCallback(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(New ThreadStart(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(lineCount As Integer)
        Console.WriteLine( _
            "Independent task printed {0} lines.", lineCount)
    End Sub
End Class
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);
    }
}
using namespace System;
using namespace System::Threading;

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

// 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 ref class ThreadWithState
{
private:
    // State information used in the task.
    String^ boilerplate;
    int value;

    // Delegate used to execute the callback method when the
    // task is complete.
    ExampleCallback^ callback;

public:
    // The constructor obtains the state information and the
    // callback delegate.
    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.
    void ThreadProc()
    {
        Console::WriteLine(boilerplate, value);
        if (callback != nullptr)
        {
            callback(1);
        }
    }
};

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

        Thread^ t = gcnew Thread(gcnew ThreadStart(tws, &ThreadWithState::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.
    //
    static void ResultCallback(int lineCount)
    {
        Console::WriteLine(
            "Independent task printed {0} lines.", lineCount);
    }
};

int main()
{
    Example::Main();
}

Vea también

Referencia

Thread

ThreadStart

ParameterizedThreadStart

Thread.Start

Otros recursos

Subprocesamiento administrado

Utilizar subprocesos y subprocesamiento

Historial de cambios

Fecha

Historial

Motivo

Mayo de 2011

Aclarar cuándo comienza a ejecutarse un subproceso.

Comentarios de los clientes.