C # - Multithreading
UMA threadé definido como o caminho de execução de um programa. Cada thread define um fluxo único de controle. Se seu aplicativo envolve operações complicadas e demoradas, geralmente é útil definir diferentes caminhos de execução ou threads, com cada thread executando um trabalho específico.
Tópicos são lightweight processes. Um exemplo comum de uso de thread é a implementação de programação simultânea por sistemas operacionais modernos. O uso de threads economiza o desperdício do ciclo da CPU e aumenta a eficiência de um aplicativo.
Até agora, escrevemos os programas em que um único thread é executado como um único processo, que é a instância em execução do aplicativo. No entanto, desta forma, o aplicativo pode executar um trabalho por vez. Para fazê-lo executar mais de uma tarefa por vez, ele pode ser dividido em threads menores.
Ciclo de Vida do Tópico
O ciclo de vida de um encadeamento começa quando um objeto da classe System.Threading.Thread é criado e termina quando o encadeamento é encerrado ou conclui a execução.
A seguir estão os vários estados no ciclo de vida de um thread -
The Unstarted State - É a situação em que a instância da thread é criada, mas o método Start não é chamado.
The Ready State - É a situação em que a thread está pronta para rodar e aguardando o ciclo da CPU.
The Not Runnable State - Um thread não é executável, quando
- O método do sono foi chamado
- Método de espera foi chamado
- Bloqueado por operações de I / O
The Dead State - É a situação em que o encadeamento conclui a execução ou é abortado.
O Tópico Principal
Em C #, o System.Threading.Threadclasse é usada para trabalhar com threads. Ele permite criar e acessar threads individuais em um aplicativo multithread. O primeiro thread a ser executado em um processo é chamado demain fio.
Quando um programa C # inicia a execução, o thread principal é criado automaticamente. Os tópicos criados usando oThreadclasse são chamadas de threads filhas da thread principal. Você pode acessar um tópico usando oCurrentThread propriedade da classe Thread.
O programa a seguir demonstra a execução do thread principal -
using System;
using System.Threading;
namespace MultithreadingApplication {
class MainThreadProgram {
static void Main(string[] args) {
Thread th = Thread.CurrentThread;
th.Name = "MainThread";
Console.WriteLine("This is {0}", th.Name);
Console.ReadKey();
}
}
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
This is MainThread
Propriedades e métodos da classe Thread
A tabela a seguir mostra alguns dos mais comumente usados properties do Thread classe -
Sr. Não. | Descrição da Propriedade |
---|---|
1 | CurrentContext Obtém o contexto atual no qual o thread está sendo executado. |
2 | CurrentCulture Obtém ou define a cultura do segmento atual. |
3 | CurrentPrinciple Obtém ou define o principal atual do thread (para segurança baseada em função). |
4 | CurrentThread Obtém o segmento em execução no momento. |
5 | CurrentUICulture Obtém ou define a cultura atual usada pelo Resource Manager para pesquisar recursos específicos da cultura em tempo de execução. |
6 | ExecutionContext Obtém um objeto ExecutionContext que contém informações sobre os vários contextos do thread atual. |
7 | IsAlive Obtém um valor que indica o status de execução do segmento atual. |
8 | IsBackground Obtém ou define um valor que indica se um thread é um thread em segundo plano ou não. |
9 | IsThreadPoolThread Obtém um valor que indica se um thread pertence ou não ao pool de threads gerenciados. |
10 | ManagedThreadId Obtém um identificador exclusivo para o segmento gerenciado atual. |
11 | Name Obtém ou define o nome do segmento. |
12 | Priority Obtém ou define um valor que indica a prioridade de agendamento de um segmento. |
13 | ThreadState Obtém um valor que contém os estados do segmento atual. |
A tabela a seguir mostra alguns dos mais comumente usados methods do Thread classe -
Sr. Não. | Método e Descrição |
---|---|
1 | public void Abort() Gera um ThreadAbortException no encadeamento em que é chamado, para iniciar o processo de encerramento do encadeamento. Chamar esse método geralmente termina o thread. |
2 | public static LocalDataStoreSlot AllocateDataSlot() Aloca um slot de dados sem nome em todos os threads. Para obter um melhor desempenho, use os campos marcados com o atributo ThreadStaticAttribute. |
3 | public static LocalDataStoreSlot AllocateNamedDataSlot(string name) Aloca um slot de dados nomeado em todos os threads. Para obter um melhor desempenho, use os campos marcados com o atributo ThreadStaticAttribute. |
4 | public static void BeginCriticalRegion() Notifica um host que a execução está prestes a entrar em uma região de código na qual os efeitos de uma interrupção de thread ou exceção não tratada podem comprometer outras tarefas no domínio do aplicativo. |
5 | public static void BeginThreadAffinity() Notifica um host que o código gerenciado está prestes a executar instruções que dependem da identidade do encadeamento do sistema operacional físico atual. |
6 | public static void EndCriticalRegion() Notifica um host que a execução está prestes a entrar em uma região de código na qual os efeitos de uma interrupção de thread ou exceção não tratada são limitados à tarefa atual. |
7 | public static void EndThreadAffinity() Notifica um host que o código gerenciado concluiu a execução de instruções que dependem da identidade do encadeamento do sistema operacional físico atual. |
8 | public static void FreeNamedDataSlot(string name) Elimina a associação entre um nome e um slot, para todos os threads no processo. Para obter um melhor desempenho, use os campos marcados com o atributo ThreadStaticAttribute. |
9 | public static Object GetData(LocalDataStoreSlot slot) Recupera o valor do slot especificado no thread atual, dentro do domínio atual do thread atual. Para obter um melhor desempenho, use os campos marcados com o atributo ThreadStaticAttribute. |
10 | public static AppDomain GetDomain() Retorna o domínio atual no qual o thread atual está sendo executado. |
11 | public static AppDomain GetDomainID() Retorna um identificador de domínio de aplicativo exclusivo |
12 | public static LocalDataStoreSlot GetNamedDataSlot(string name) Procura um slot de dados nomeado. Para obter um melhor desempenho, use os campos marcados com o atributo ThreadStaticAttribute. |
13 | public void Interrupt() Interrompe um thread que está no estado de thread WaitSleepJoin. |
14 | public void Join() Bloqueia o encadeamento de chamada até que um encadeamento termine, enquanto continua a realizar o bombeamento COM e SendMessage padrão. Este método possui diferentes formas sobrecarregadas. |
15 | public static void MemoryBarrier() Sincroniza o acesso à memória da seguinte maneira: O processador que executa o thread atual não pode reordenar as instruções de forma que os acessos à memória antes da chamada para MemoryBarrier sejam executados após os acessos à memória que seguem a chamada para MemoryBarrier. |
16 | public static void ResetAbort() Cancela um Abort solicitado para o segmento atual. |
17 | public static void SetData(LocalDataStoreSlot slot, Object data) Define os dados no slot especificado no segmento em execução no momento, para o domínio atual desse segmento. Para melhor desempenho, use os campos marcados com o atributo ThreadStaticAttribute. |
18 | public void Start() Inicia um tópico. |
19 | public static void Sleep(int millisecondsTimeout) Faz o encadeamento pausar por um período de tempo. |
20 | public static void SpinWait(int iterations) Faz com que uma thread espere o número de vezes definido pelo parâmetro iterations |
21 | public static byte VolatileRead(ref byte address) public static double VolatileRead(ref double address) public static int VolatileRead(ref int address) public static Object VolatileRead(ref Object address) Lê o valor de um campo. O valor é o último gravado por qualquer processador em um computador, independentemente do número de processadores ou do estado do cache do processador. Este método possui diferentes formas sobrecarregadas. Apenas alguns são fornecidos acima. |
22 | public static void VolatileWrite(ref byte address,byte value) public static void VolatileWrite(ref double address, double value) public static void VolatileWrite(ref int address, int value) public static void VolatileWrite(ref Object address, Object value) Grava um valor em um campo imediatamente, de forma que o valor fique visível para todos os processadores no computador. Este método possui diferentes formas sobrecarregadas. Apenas alguns são fornecidos acima. |
23 | public static bool Yield() Faz com que o thread de chamada produza a execução de outro thread que está pronto para ser executado no processador atual. O sistema operacional seleciona o segmento ao qual ceder. |
Criando Threads
Threads são criados estendendo a classe Thread. A classe Thread estendida então chama oStart() método para iniciar a execução do thread filho.
O programa a seguir demonstra o conceito -
using System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
Console.WriteLine("Child thread starts");
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
In Main: Creating the Child thread
Child thread starts
Gerenciando Threads
A classe Thread fornece vários métodos para gerenciar threads.
O exemplo a seguir demonstra o uso do sleep() método para fazer uma pausa de thread por um período específico de tempo.
using System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
Console.WriteLine("Child thread starts");
// the thread is paused for 5000 milliseconds
int sleepfor = 5000;
Console.WriteLine("Child Thread Paused for {0} seconds", sleepfor / 1000);
Thread.Sleep(sleepfor);
Console.WriteLine("Child thread resumes");
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes
Destruindo Threads
o Abort() método é usado para destruir threads.
O tempo de execução aborta o encadeamento lançando um ThreadAbortException. Esta exceção não pode ser detectada, o controle é enviado para o bloco finally , se houver.
O programa a seguir ilustra isso -
using System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
try {
Console.WriteLine("Child thread starts");
// do some work, like counting to 10
for (int counter = 0; counter <= 10; counter++) {
Thread.Sleep(500);
Console.WriteLine(counter);
}
Console.WriteLine("Child Thread Completed");
} catch (ThreadAbortException e) {
Console.WriteLine("Thread Abort Exception");
} finally {
Console.WriteLine("Couldn't catch the Thread Exception");
}
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
//stop the main thread for some time
Thread.Sleep(2000);
//now abort the child
Console.WriteLine("In Main: Aborting the Child thread");
childThread.Abort();
Console.ReadKey();
}
}
}
Quando o código acima é compilado e executado, ele produz o seguinte resultado -
In Main: Creating the Child thread
Child thread starts
0
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception