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.
Enfileirar uma tarefa para execução por ThreadPool segmentos, com o RegisterWaitForSingleObject método.
Sinalização de uma tarefa para executar com AutoResetEvent. Consulte EventWaitHandle AutoResetEvent e ManualResetEvent.
Tratamento de tempos limite e sinais com um WaitOrTimerCallback delegado.
Cancelando uma tarefa na fila com RegisteredWaitHandle.
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
);
}
}