Partilhar via


O pool gerenciado thread

The ThreadPool classe fornece o aplicativo com um pool de trabalho thread s que são gerenciado pelo sistema, permitindo que você se concentre nas tarefas de aplicativos em vez de thread gerenciamento. Se você tiver tarefas curtas que exigem processamento em segundo plano, o pool de thread gerenciado é uma maneira fácil para usufruir os vários segmentos.

Observação:

Iniciando com o .NET Framework versão 2.0 Service Pack 1, a taxa de transferência do thread pool é significativamente aprimorado em três áreas principais que foram identificadas sistema autônomo afunilamentos em versões anteriores dos .NET Framework: tarefas de enfileirar de mensagens, expedição thread pool thread s e conclusão de E/s expedição thread s.Para usar esta funcionalidade, seu aplicativo deve visar o .NET Framework versão 3.5. Para obter mais informações, consulte Arquitetura do .NET Framework 3.5.

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

O .NET estrutura usa thread pool thread s para várias finalidades, inclusive conclusão de E/s assíncrona, retornos de chamada timer, registrados espere operações, chamadas de método assíncrono usando delegados e System.Net conexões de soquete.

Quando não usar pool thread thread s

Existem vários cenários em que é apropriado para criar e gerenciar seu próprios thread s em vez de usar thread pool thread s:

  • Você precisa primeiro um plano thread.

  • Você precisa de um thread tenham uma determinada prioridade.

  • Você tem tarefas que fazem com que o thread a bloquear por longos períodos de time.O thread pool tem um número máximo de thread s, para que um grande número de bloqueados thread pool thread s podem impedir que as tarefas seja iniciado.

  • Você precisa colocar threads em um apartment single-threaded.All ThreadPool segmentos estão multithreaded apartment.

  • Você precisa ter uma identidade estável associada a thread, ou para dedicar um thread a uma tarefa.

Pool thread características

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

Há apenas um thread pool por processo.

Exceções no pool thread thread s

Exceções não tratadas em thread pool thread s terminar the processo.Há três exceções a essa regra:

  • A ThreadAbortException é acionada em um thread do pool de threads, porque Abort foi chamado.

  • An AppDomainUnloadedException é acionada em um thread do pool de threads, porque o domínio do aplicativo está sendo descarregado.

  • O Common linguagem tempo de execução ou um processo de host encerra o thread.

Para obter mais informações, consulte Exceções em threads gerenciado.

Observação:

Nas versões do .NET estrutura 1.0 e 1.1, o Common linguagem tempo de execução silenciosamente ajusta o registro de exceções sem tratamento em threads do pool de threads.Isso pode corromper o estado do aplicativo e, eventualmente, fazer com que os aplicativos parar, que podem ser muito difícil depurar.

Número máximo de pool thread thread s

O número de operações que podem ser colocados na fila para o thread pool é limitado apenas pela memória disponível; no entanto, o thread pool limita o número de s thread que podem estar ativas no processo simultaneamente.Por padrão, o limite é de 25 threads de trabalho por CPU e 1.000 threads de conclusão E/s.

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

Observação:

Nas versões de .NET estrutura 1.0 e 1.1, o dimensionar do thread pool não pode ser definida no código gerenciado.Código que hospeda o common linguagem tempo de execução pode conjunto o dimensionar usando CorSetMaxThreads, definido no mscoree.h.

Número mínimo de segmentos ociosos

O thread pool também mantém um número mínimo de disponível thread s, mesmo quando todos os thread s são ocioso, para que na fila de tarefas pode iniciar imediatamente.Threads ociosos desse mínimo são encerrados para economizar recursos do sistema.Por padrão, um thread ocioso é mantido por processador.

O pool de segmentos possui um atraso interno (meio segundo no .NET estrutura versão 2.0) antes de iniciar novos threads ociosos.Se o seu aplicativo periodicamente iniciar várias tarefas em um curto período de time, um pequeno aumento no número de segmentos ociosos pode produzir um aumento significativo no throughput.Definindo o número de threads ociosos muito altas consome recursos do sistema desnecessariamente.

Você pode controlar o número de s thread ocioso mantido pelo thread pool usando o GetMinThreads e SetMinThreads métodos.

Observação:

No .NET estrutura versão 1.0, o número mínimo de threads ociosos não pode ser definido.

Ignorando verificações de segurança

O thread pool também fornece o ThreadPool.UnsafeQueueUserWorkItem e ThreadPool.UnsafeRegisterWaitForSingleObject métodos. Use esses métodos apenas quando tiver certeza de que a pilha do chamador é irrelevante para quaisquer verificações de segurança realizadas durante a execução de tarefa na fila.QueueUserWorkItemand RegisterWaitForSingleObject ambos capturam a pilha do chamador, qual é 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, todo o conjunto deve ser marcado.Embora a verificação fornece segurança, ele também tem um custo de desempenho.

Usando o pool thread

Usar o pool de segmentos chamando ThreadPool.QueueUserWorkItem no código gerenciado (ou CorQueueUserWorkItem do código não gerenciado), passando um WaitCallback delegado que representa o método que executa a tarefa. Você também pode enfileirar itens de trabalho relacionadas a uma operação de espera usando o ThreadPool.RegisterWaitForSingleObject método e passar um WaitHandle que, quando sinalizado ou quando o tempo limite, gera uma telefonar ao método representado pela WaitOrTimerCallback delegado. Em ambos os casos, o pool de segmentos utiliza um thread de segundo plano para invocar o método de retorno de chamada.

Exemplos de ThreadPool

Os exemplos de três código a seguir demonstram o QueueUserWorkItem e RegisterWaitForSingleObject métodos.

O primeiro exemplo coloca uma tarefa muito simples, representada pelo 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.");
    }
}

Fornecendo dados de tarefas para QueueUserWorkItem

O exemplo de código a seguir usa o QueueUserWorkItem método para uma tarefa na fila 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); 
    }
}

RegisterWaitForSingleObject

O exemplo a seguir demonstra 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
        );
    }
}

Consulte também

Conceitos

Segmentos e Threading

E/S de Arquivo Assíncrono

Temporizadores

Referência

ThreadPool

Outros recursos

Recursos e objetos de Threading