O Pool de segmentos gerenciado

O ThreadPool classe fornece o seu aplicativo com um pool de threads de trabalho que são gerenciados pelo sistema, permitindo que você se concentre nas tarefas do aplicativo em vez de gerenciamento de thread. Se você tiver tarefas curtas que exigem o processamento em segundo plano, o pool de segmentos gerenciado é uma maneira fácil de tirar proveito de vários segmentos. Por exemplo, começando com o .NET Framework versão 4 você pode criar Task e Task<TResult> objetos, que executam tarefas assíncronas em threads do pool de threads.

Observação

Começando com o .NET Framework versão 2.0 Service Pack 1, a taxa de transferência do pool de threads é aprimorada significativamente em três áreas principais que foram identificadas como afunilamentos nas versões anteriores da .NET Framework: tarefas de enfileiramento de mensagens, threads do pool de expedição e despacho de threads de conclusão de e/S.Para usar esta funcionalidade, seu aplicativo deve visar o .NET Framework versão 3.5 ou posterior.

Para tarefas em segundo plano que interagem com a interface do usuário, o.NET Framework versão 2.0 também fornece a BackgroundWorker classe, que se comunica usando eventos disparados no segmento de interface de usuário.

A.NET Framework usa os threads do pool para muitos propósitos, incluindo a conclusão de e/S assíncrona, operações de espera de retornos de chamada timer, registrados, chamadas de método assíncrono usando delegados, e System.Net conexões de soquete.

Quando não usar Threads do Pool de segmentos

Há vários cenários em que é apropriado criar e gerenciar seus próprios segmentos em vez de usar os threads do pool:

  • Você precisa de um segmento de primeiro plano.

  • Você precisa de um segmento de uma determinada prioridade.

  • Você tem tarefas que fazem com que o segmento de bloquear por longos períodos de tempo. O pool de segmentos possui um número máximo de threads, portanto, um grande número de threads do pool de threads bloqueados pode impedir que as tarefas iniciando.

  • É necessário que você coloque a single-threaded apartment de threads. Todos os ThreadPool segmentos estão no apartamento multithreaded.

  • Você precisa ter uma identidade estável associada ao segmento ou dedicar um segmento a uma tarefa.

As características do Pool de segmentos.

Threads do pool são segmentos de plano de fundo. Consulte Segmentos de Primeiro Plano e Plano de Fundo. Cada thread usa o tamanho de pilha padrão, é executado com a prioridade padrão e está em multithreaded apartment.

Há um pool de apenas um segmento por processo.

Exceções no Thread do Pool de Threads

Exceções sem tratamento em threads do pool terminar o processo. Há três exceções a essa regra:

  • A ThreadAbortException é lançada em um thread do pool, pois Abort foi chamado.

  • Um AppDomainUnloadedException é lançada em um thread do pool, porque o domínio do aplicativo está sendo descarregado.

  • O common language runtime ou um processo de host encerra o thread.

Para obter mais informações, consulte Exceções de Threads gerenciados.

Observação

No.NET Framework versões 1.0 e 1.1, o common language runtime silenciosamente intercepta as exceções sem tratamento em threads do pool.Isso pode corromper o estado do aplicativo e eventualmente causar aplicativos travar, que podem ser muito difícil de depurar.

Número máximo de Threads do Pool

O número de operações que podem ser enfileiradas para o pool de segmentos é limitado apenas pela memória disponível; No entanto, o pool de segmentos limita o número de segmentos podem estar ativas no processo simultaneamente. Começando com o .NET Framework versão 4, o tamanho padrão do pool de threads para um processo depende de vários fatores, como o tamanho do espaço de endereço virtual. Um processo pode chamar o GetMaxThreads método para determinar o número de threads.

Você pode controlar o número máximo de segmentos usando o GetMaxThreads e SetMaxThreads métodos.

Observação

No.NET Framework versões 1.0 e 1.1, o tamanho do pool de segmentos não pode ser definido no código gerenciado.Código que hospeda o common language runtime pode definir o tamanho usando CorSetMaxThreads, definido em mscoree.h.

Mínimos de Pool de segmentos.

O pool de segmentos fornece novos segmentos de trabalho ou os threads de conclusão de e/S sob demanda até alcançar um mínimo especificado para cada categoria. Você pode usar o GetMinThreads método para obter esses valores mínimos.

Observação

Quando a demanda seja baixa, o número real de threads do pool pode cair os valores mínimos.

Quando um mínimo é atingido, o pool de segmentos pode criar threads adicionais ou aguarde até que a completar algumas tarefas. Começando com o .NET Framework 4, o pool de segmentos cria e destrói segmentos de trabalho a fim de otimizar o throughput, que é definido como o número de tarefas que concluir por unidade de tempo. Muito poucos segmentos podem não fazer melhor uso dos recursos disponíveis, enquanto muitos segmentos podem aumentar a contenção de recursos.

Observação de cuidadoCuidado

Você pode usar o SetMinThreads método para aumentar o número mínimo de segmentos ociosos.No entanto, esses valores de aumento desnecessariamente podem causar problemas de desempenho.Se muitas tarefas iniciem ao mesmo tempo, todos eles podem parecer ser lenta.Na maioria dos casos o pool de threads terão melhor desempenho com seu próprio algoritmo de alocação de segmentos.

Ignorando as verificações de segurança

O pool de segmentos também fornece a ThreadPool.UnsafeQueueUserWorkItem e ThreadPool.UnsafeRegisterWaitForSingleObject métodos. Use esses métodos apenas quando tiver certeza de que a pilha do chamador é irrelevante para verificações de segurança realizadas durante a execução da tarefa na fila. QueueUserWorkIteme RegisterWaitForSingleObject ambos captura a pilha do chamador, que é mesclada na pilha de thread do pool quando o segmento começa a executar uma tarefa. Se uma verificação de segurança for necessária, toda a pilha deve ser marcada. Embora a verificação fornece segurança, ele também tem um custo de desempenho.

Usando o Pool de threads

Começando com o .NET Framework 4, a maneira mais fácil de usar o pool de segmentos é usar o Biblioteca paralela de tarefas. Por padrão, os tipos de bibliotecas paralelas como Task e Task<TResult> usar threads do pool para executar tarefas. Você também pode usar o pool de segmentos chamando ThreadPool.QueueUserWorkItem do código gerenciado (ou CorQueueUserWorkItem do código não gerenciado) e passando um WaitCallback delegar que representa o método que realiza a tarefa. Outra maneira de usar o pool de segmentos é enfileirar itens de trabalho que estão relacionados a uma operação de espera usando o ThreadPool.RegisterWaitForSingleObject método e passar um WaitHandle que, quando sinalizado ou expirou, chama o método representado pela WaitOrTimerCallback delegate. A thread do pool de segmentos são usados para chamar os métodos de retorno de chamada.

Exemplos de ThreadPool

Os exemplos de código nesta seção demonstram o pool de segmentos usando o Task classe, o ThreadPool.QueueUserWorkItem método e o ThreadPool.RegisterWaitForSingleObject método.

  • Executando tarefas assíncronas com a biblioteca paralela de tarefas

  • A execução de código de forma assíncrona com QueueUserWorkItem

  • O fornecimento de dados de tarefas para QueueUserWorkItem

  • Usando RegisterWaitForSingleObject

Executando tarefas assíncronas com a biblioteca paralela de tarefas

O exemplo a seguir mostra como criar e usar um Task objeto chamando o TaskFactory.StartNew método. Para obter um exemplo que usa o Task<TResult> classe para retornar um valor de uma tarefa assíncrona, consulte Como: Retornar um valor de uma tarefa..

Imports System.Threading
Imports System.Threading.Tasks
Module StartNewDemo

    ' Demonstrated features:
    '   Task ctor()
    '   Task.Factory
    '   Task.Wait()
    '   Task.RunSynchronously()
    ' Expected results:
    '   Task t1 (alpha) is created unstarted.
    '   Task t2 (beta) is created started.
    '   Task t1's (alpha) start is held until after t2 (beta) is started.
    '   Both tasks t1 (alpha) and t2 (beta) are potentially executed on threads other than the main thread on multi-core machines.
    '   Task t3 (gamma) is executed synchronously on the main thread.
    ' Documentation:
    '   https://msdn.microsoft.com/en-us/library/system.threading.tasks.task_members(VS.100).aspx
    Private Sub Main()
        Dim action As Action(Of Object) = Sub(obj As Object)
                                              Console.WriteLine("Task={0}, obj={1}, Thread={2}", Task.CurrentId, obj.ToString(), Thread.CurrentThread.ManagedThreadId)
                                          End Sub

        ' Construct an unstarted task
        Dim t1 As New Task(action, "alpha")

        ' Cosntruct a started task
        Dim t2 As Task = Task.Factory.StartNew(action, "beta")

        ' Block the main thread to demonstate that t2 is executing
        t2.Wait()

        ' Launch t1 
        t1.Start()

        Console.WriteLine("t1 has been launched. (Main Thread={0})", Thread.CurrentThread.ManagedThreadId)

        ' Wait for the task to finish.
        ' You may optionally provide a timeout interval or a cancellation token
        ' to mitigate situations when the task takes too long to finish.
        t1.Wait()

        ' Construct an unstarted task
        Dim t3 As New Task(action, "gamma")

        ' Run it synchronously
        t3.RunSynchronously()

        ' Although the task was run synchrounously, it is a good practice to wait for it which observes for 
        ' exceptions potentially thrown by that task.
        t3.Wait()
    End Sub


End Module
using System;
using System.Threading;
using System.Threading.Tasks;

class StartNewDemo
{
    // Demonstrated features:
    //      Task ctor()
    //      Task.Factory
    //      Task.Wait()
    //      Task.RunSynchronously()
    // Expected results:
    //      Task t1 (alpha) is created unstarted.
    //      Task t2 (beta) is created started.
    //      Task t1's (alpha) start is held until after t2 (beta) is started.
    //      Both tasks t1 (alpha) and t2 (beta) are potentially executed on threads other than the main thread on multi-core machines.
    //      Task t3 (gamma) is executed synchronously on the main thread.
    // Documentation:
    //      https://msdn.microsoft.com/en-us/library/system.threading.tasks.task_members(VS.100).aspx
    static void Main()
    {
        Action<object> action = (object obj) =>
        {
            Console.WriteLine("Task={0}, obj={1}, Thread={2}", Task.CurrentId, obj.ToString(), Thread.CurrentThread.ManagedThreadId);
        };

        // Construct an unstarted task
        Task t1 = new Task(action, "alpha");

        // Cosntruct a started task
        Task t2 = Task.Factory.StartNew(action, "beta");

        // Block the main thread to demonstate that t2 is executing
        t2.Wait();

        // Launch t1 
        t1.Start();

        Console.WriteLine("t1 has been launched. (Main Thread={0})", Thread.CurrentThread.ManagedThreadId);

        // Wait for the task to finish.
        // You may optionally provide a timeout interval or a cancellation token
        // to mitigate situations when the task takes too long to finish.
        t1.Wait();

        // Construct an unstarted task
        Task t3 = new Task(action, "gamma");

        // Run it synchronously
        t3.RunSynchronously();

        // Although the task was run synchrounously, it is a good practice to wait for it which observes for 
        // exceptions potentially thrown by that task.
        t3.Wait();
    }


}

A execução de código de forma assíncrona com QueueUserWorkItem

O exemplo a seguir coloca uma tarefa muito simple, representada pela ThreadProc método, usando o QueueUserWorkItem método.

Imports System
Imports System.Threading

Public Class Example
    Public Shared Sub Main()
        ' Queue the task.
        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ThreadProc))

        Console.WriteLine("Main thread does some work, then sleeps.")
        ' If you comment out the Sleep, the main thread exits before
        ' the thread pool task runs.  The thread pool uses background
        ' threads, which do not keep the application running.  (This
        ' is a simple example of a race condition.)
        Thread.Sleep(1000)

        Console.WriteLine("Main thread exits.")
    End Sub

    ' This thread procedure performs the task.
    Shared Sub ThreadProc(stateInfo As Object)
        ' No state object was passed to QueueUserWorkItem, so
        ' stateInfo is null.
        Console.WriteLine("Hello from the thread pool.")
    End Sub
End Class
using System;
using System.Threading;

public class Example
{
    public static void Main()
    {
        // Queue the task.
        ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));

        Console.WriteLine("Main thread does some work, then sleeps.");
        // If you comment out the Sleep, the main thread exits before
        // the thread pool task runs.  The thread pool uses background
        // threads, which do not keep the application running.  (This
        // is a simple example of a race condition.)
        Thread.Sleep(1000);

        Console.WriteLine("Main thread exits.");
    }

    // This thread procedure performs the task.
    static void ThreadProc(Object stateInfo)
    {
        // No state object was passed to QueueUserWorkItem, so
        // stateInfo is null.
        Console.WriteLine("Hello from the thread pool.");
    }
}
using namespace System;
using namespace System::Threading;

public ref class Example
{
public:
    static void Main()
    {
        // Queue the task.
        ThreadPool::QueueUserWorkItem(gcnew WaitCallback(&ThreadProc));

        Console::WriteLine("Main thread does some work, then sleeps.");
        // If you comment out the Sleep, the main thread exits before
        // the thread pool task runs.  The thread pool uses background
        // threads, which do not keep the application running.  (This
        // is a simple example of a race condition.)
        Thread::Sleep(1000);

        Console::WriteLine("Main thread exits.");
    }

    // This thread procedure performs the task.
    static void ThreadProc(Object^ stateInfo)
    {
        // No state object was passed to QueueUserWorkItem, so
        // stateInfo is null.
        Console::WriteLine("Hello from the thread pool.");
    }
};

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

O fornecimento de dados de tarefas para QueueUserWorkItem

O seguinte exemplo de código usa a QueueUserWorkItem método para enfileirar uma tarefa e fornecer os dados para a tarefa.

Imports System
Imports System.Threading

' TaskInfo holds state information for a task that will be
' executed by a ThreadPool thread.
Public class TaskInfo
    ' State information for the task.  These members
    ' can be implemented as read-only properties, read/write
    ' properties with validation, and so on, as required.
    Public Boilerplate As String
    Public Value As Integer

    ' Public constructor provides an easy way to supply all
    ' the information needed for the task.
    Public Sub New(text As String, number As Integer)
        Boilerplate = text
        Value = number
    End Sub
End Class

Public Class Example
    Public Shared Sub Main()
        ' Create an object containing the information needed
        ' for the task.
        Dim ti As New TaskInfo("This report displays the number {0}.", 42)

        ' Queue the task and data.
        If ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ThreadProc), ti) Then
            Console.WriteLine("Main thread does some work, then sleeps.")

            ' If you comment out the Sleep, the main thread exits before
            ' the ThreadPool task has a chance to run.  ThreadPool uses
            ' background threads, which do not keep the application
            ' running.  (This is a simple example of a race condition.)
            Thread.Sleep(1000)

            Console.WriteLine("Main thread exits.")
        Else
            Console.WriteLine("Unable to queue ThreadPool request.")
        End If
    End Sub

    ' The thread procedure performs the independent task, in this case
    ' formatting and printing a very simple report.
    '
    Shared Sub ThreadProc(stateInfo As Object)
        Dim ti As TaskInfo = CType(stateInfo, TaskInfo)
        Console.WriteLine(ti.Boilerplate, ti.Value)
    End Sub
End Class
using System;
using System.Threading;

// TaskInfo holds state information for a task that will be
// executed by a ThreadPool thread.
public class TaskInfo
{
    // State information for the task.  These members
    // can be implemented as read-only properties, read/write
    // properties with validation, and so on, as required.
    public string Boilerplate;
    public int Value;

    // Public constructor provides an easy way to supply all
    // the information needed for the task.
    public TaskInfo(string text, int number)
    {
        Boilerplate = text;
        Value = number;
    }
}

public class Example
{
    public static void Main()
    {
        // Create an object containing the information needed
        // for the task.
        TaskInfo ti = new TaskInfo("This report displays the number {0}.", 42);

        // Queue the task and data.
        if (ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), ti))
        {
            Console.WriteLine("Main thread does some work, then sleeps.");

            // If you comment out the Sleep, the main thread exits before
            // the ThreadPool task has a chance to run.  ThreadPool uses
            // background threads, which do not keep the application
            // running.  (This is a simple example of a race condition.)
            Thread.Sleep(1000);

            Console.WriteLine("Main thread exits.");
        }
        else
        {
            Console.WriteLine("Unable to queue ThreadPool request.");
        }
    }

    // The thread procedure performs the independent task, in this case
    // formatting and printing a very simple report.
    //
    static void ThreadProc(Object stateInfo)
    {
        TaskInfo ti = (TaskInfo) stateInfo;
        Console.WriteLine(ti.Boilerplate, ti.Value);
    }
}
using namespace System;
using namespace System::Threading;

// TaskInfo holds state information for a task that will be
// executed by a ThreadPool thread.
public ref class TaskInfo
{
    // State information for the task.  These members
    // can be implemented as read-only properties, read/write
    // properties with validation, and so on, as required.
public:
    String^ Boilerplate;
    int Value;

    // Public constructor provides an easy way to supply all
    // the information needed for the task.
    TaskInfo(String^ text, int number)
    {
        Boilerplate = text;
        Value = number;
    }
};

public ref class Example
{
public:
    static void Main()
    {
        // Create an object containing the information needed
        // for the task.
        TaskInfo^ ti = gcnew TaskInfo("This report displays the number {0}.", 42);

        // Queue the task and data.
        if (ThreadPool::QueueUserWorkItem(gcnew WaitCallback(&ThreadProc), ti))
        {
            Console::WriteLine("Main thread does some work, then sleeps.");

            // If you comment out the Sleep, the main thread exits before
            // the ThreadPool task has a chance to run.  ThreadPool uses
            // background threads, which do not keep the application
            // running.  (This is a simple example of a race condition.)
            Thread::Sleep(1000);

            Console::WriteLine("Main thread exits.");
        }
        else
        {
            Console::WriteLine("Unable to queue ThreadPool request.");
        }
    }

    // The thread procedure performs the independent task, in this case
    // formatting and printing a very simple report.
    //
    static void ThreadProc(Object^ stateInfo)
    {
        TaskInfo^ ti = (TaskInfo^) stateInfo;
        Console::WriteLine(ti->Boilerplate, ti->Value);
    }
};

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

Usando RegisterWaitForSingleObject

O exemplo a seguir demonstra os vários recursos de threads.

Imports System
Imports System.Threading

' TaskInfo contains data that will be passed to the callback
' method.
Public Class TaskInfo
    public Handle As RegisteredWaitHandle = Nothing
    public OtherInfo As String = "default"
End Class

Public Class Example
    Public Shared Sub Main()
        ' The main thread uses AutoResetEvent to signal the
        ' registered wait handle, which executes the callback
        ' method.
        Dim ev As New AutoResetEvent(false)

        Dim ti As New TaskInfo()
        ti.OtherInfo = "First task"
        ' The TaskInfo for the task includes the registered wait
        ' handle returned by RegisterWaitForSingleObject.  This
        ' allows the wait to be terminated when the object has
        ' been signaled once (see WaitProc).
        ti.Handle = ThreadPool.RegisterWaitForSingleObject( _
            ev, _
            New WaitOrTimerCallback(AddressOf WaitProc), _
            ti, _
            1000, _
            false _
        )

        ' The main thread waits about three seconds, to demonstrate 
        ' the time-outs on the queued task, and then signals.
        Thread.Sleep(3100)
        Console.WriteLine("Main thread signals.")
        ev.Set()

        ' The main thread sleeps, which should give the callback
        ' method time to execute.  If you comment out this line, the
        ' program usually ends before the ThreadPool thread can execute.
        Thread.Sleep(1000)
        ' If you start a thread yourself, you can wait for it to end
        ' by calling Thread.Join.  This option is not available with 
        ' thread pool threads.
    End Sub

    ' The callback method executes when the registered wait times out,
    ' or when the WaitHandle (in this case AutoResetEvent) is signaled.
    ' WaitProc unregisters the WaitHandle the first time the event is 
    ' signaled.
    Public Shared Sub WaitProc(state As Object, timedOut As Boolean)
        ' The state object must be cast to the correct type, because the
        ' signature of the WaitOrTimerCallback delegate specifies type
        ' Object.
        Dim ti As TaskInfo = CType(state, TaskInfo)

        Dim cause As String = "TIMED OUT"
        If Not timedOut Then
            cause = "SIGNALED"
            ' If the callback method executes because the WaitHandle is
            ' signaled, stop future execution of the callback method
            ' by unregistering the WaitHandle.
            If Not ti.Handle Is Nothing Then
                ti.Handle.Unregister(Nothing)
            End If
        End If 

        Console.WriteLine("WaitProc( {0} ) executes on thread {1}; cause = {2}.", _
            ti.OtherInfo, _
            Thread.CurrentThread.GetHashCode().ToString(), _
            cause _
        )
    End Sub
End Class
using System;
using System.Threading;

// TaskInfo contains data that will be passed to the callback
// method.
public class TaskInfo
{
    public RegisteredWaitHandle Handle = null;
    public string OtherInfo = "default";
}

public class Example
{
    public static void Main(string[] args)
    {
        // The main thread uses AutoResetEvent to signal the
        // registered wait handle, which executes the callback
        // method.
        AutoResetEvent ev = new AutoResetEvent(false);

        TaskInfo ti = new TaskInfo();
        ti.OtherInfo = "First task";
        // The TaskInfo for the task includes the registered wait
        // handle returned by RegisterWaitForSingleObject.  This
        // allows the wait to be terminated when the object has
        // been signaled once (see WaitProc).
        ti.Handle = ThreadPool.RegisterWaitForSingleObject(
            ev,
            new WaitOrTimerCallback(WaitProc),
            ti,
            1000,
            false );

        // The main thread waits three seconds, to demonstrate the
        // time-outs on the queued thread, and then signals.
        Thread.Sleep(3100);
        Console.WriteLine("Main thread signals.");
        ev.Set();

        // The main thread sleeps, which should give the callback
        // method time to execute.  If you comment out this line, the
        // program usually ends before the ThreadPool thread can execute.
        Thread.Sleep(1000);
        // If you start a thread yourself, you can wait for it to end
        // by calling Thread.Join.  This option is not available with
        // thread pool threads.
    }

    // The callback method executes when the registered wait times out,
    // or when the WaitHandle (in this case AutoResetEvent) is signaled.
    // WaitProc unregisters the WaitHandle the first time the event is
    // signaled.
    public static void WaitProc(object state, bool timedOut)
    {
        // The state object must be cast to the correct type, because the
        // signature of the WaitOrTimerCallback delegate specifies type
        // Object.
        TaskInfo ti = (TaskInfo) state;

        string cause = "TIMED OUT";
        if (!timedOut)
        {
            cause = "SIGNALED";
            // If the callback method executes because the WaitHandle is
            // signaled, stop future execution of the callback method
            // by unregistering the WaitHandle.
            if (ti.Handle != null)
                ti.Handle.Unregister(null);
        }

        Console.WriteLine("WaitProc( {0} ) executes on thread {1}; cause = {2}.",
            ti.OtherInfo,
            Thread.CurrentThread.GetHashCode().ToString(),
            cause
        );
    }
}
using namespace System;
using namespace System::Threading;

// TaskInfo contains data that will be passed to the callback
// method.
public ref class TaskInfo
{
public:
    static RegisteredWaitHandle^ Handle = nullptr;
    static String^ OtherInfo = "default";
};

public ref class Example
{
public:
    static void Main()
    {
        // The main thread uses AutoResetEvent to signal the
        // registered wait handle, which executes the callback
        // method.
        AutoResetEvent^ ev = gcnew AutoResetEvent(false);

        TaskInfo^ ti = gcnew TaskInfo();
        ti->OtherInfo = "First task";
        // The TaskInfo for the task includes the registered wait
        // handle returned by RegisterWaitForSingleObject.  This
        // allows the wait to be terminated when the object has
        // been signaled once (see WaitProc).
        ti->Handle = ThreadPool::RegisterWaitForSingleObject(
            ev,
            gcnew WaitOrTimerCallback(&WaitProc),
            ti,
            1000,
            false );

        // The main thread waits three seconds, to demonstrate the
        // time-outs on the queued thread, and then signals.
        Thread::Sleep(3100);
        Console::WriteLine("Main thread signals.");
        ev->Set();

        // The main thread sleeps, which should give the callback
        // method time to execute.  If you comment out this line, the
        // program usually ends before the ThreadPool thread can execute.
        Thread::Sleep(1000);
        // If you start a thread yourself, you can wait for it to end
        // by calling Thread.Join.  This option is not available with
        // thread pool threads.
    }

    // The callback method executes when the registered wait times out,
    // or when the WaitHandle (in this case AutoResetEvent) is signaled.
    // WaitProc unregisters the WaitHandle the first time the event is
    // signaled.
    static void WaitProc(Object^ state, bool timedOut)
    {
        // The state object must be cast to the correct type, because the
        // signature of the WaitOrTimerCallback delegate specifies type
        // Object.
        TaskInfo^ ti = (TaskInfo^) state;

        String^ cause = "TIMED OUT";
        if (!timedOut)
        {
            cause = "SIGNALED";
            // If the callback method executes because the WaitHandle is
            // signaled, stop future execution of the callback method
            // by unregistering the WaitHandle.
            if (ti->Handle != nullptr)
                ti->Handle->Unregister(nullptr);
        }

        Console::WriteLine("WaitProc( {0} ) executes on thread {1}; cause = {2}.",
            ti->OtherInfo,
            Thread::CurrentThread->GetHashCode().ToString(),
            cause
        );
    }
};

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

Consulte também

Tarefas

Como: Retornar um valor de uma tarefa.

Referência

ThreadPool

Task

Task<TResult>

Conceitos

Biblioteca paralela de tarefas

Biblioteca paralela de tarefas

Segmentos e Threading

E/S de Arquivo Assíncrono

Temporizadores

Outros recursos

Threading objetos e recursos

Histórico de alterações

Date

History

Motivo

Setembro de 2010

Corrigido o tamanho padrão desatualizados e informações desatualizadas sobre a criação de novos segmentos. Exemplo adicional de Biblioteca paralela de tarefas.

Correção de bug de conteúdo.