Concorrência e Multithreading em C#: do A ao Z — Guia Completo

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que a concorrência é necessária em C#?

Os aplicativos modernos cada vez mais exigem a execução de várias operações simultaneamente. O usuário espera que a interface não "trave" ao carregar dados, e que o servidor consiga processar milhares de requisições em paralelo. Em C# (.NET), para resolver esses problemas, utiliza-se concorrência — a capacidade do programa de executar várias tarefas em intervalos de tempo sobrepostos — e multithreading — a implementação da concorrência usando múltiplas threads de execução.

Neste artigo, abordaremos os conceitos-chave: desde os básicos Thread até os modernos async/await e Parallel. Você aprenderá como escolher a ferramenta certa para cada tarefa e evitar erros comuns, como deadlocks e race conditions.



1. Fundamentos: Thread e ThreadPool

Trabalhando com threads via Thread

A classe System.Threading.Thread é a forma mais de baixo nível de criar threads. Cada thread tem sua própria pilha e é executada de forma independente. Exemplo de criação e inicialização de uma thread:

using System;using System.Threading;

class Program{ static void Main() { Thread thread = new Thread(DoWork); thread.Start(); // A thread principal continua o trabalho for (int i = 0; i < 5; i++) { Console.WriteLine($"Thread principal: {i}"); Thread.Sleep(100); } thread.Join(); // Aguarda a conclusão da thread filha }

static void DoWork() { for (int i = 0; i < 5; i++) { Console.WriteLine($"Thread de trabalho: {i}"); Thread.Sleep(150); } }}

Importante: Criar uma nova thread é uma operação cara. Para a criação frequente de threads de curta duração, é melhor usar ThreadPool.



ThreadPool — pool de threads

ThreadPool gerencia um conjunto de threads de trabalho que são reutilizadas. Isso é mais eficiente do que criar Thread manualmente. Exemplo:

ThreadPool.QueueUserWorkItem(state =>{    Console.WriteLine("Tarefa sendo executada no pool de threads");    Thread.Sleep(500);    Console.WriteLine("Tarefa concluída");});

Console.WriteLine("Thread principal continua o trabalho");Console.ReadKey();

Limitação: Você não pode controlar diretamente a prioridade ou o nome de uma thread do pool. Para um controle mais refinado, use Task.



2. Task e Task Parallel Library (TPL)

Task — abordagem moderna

A partir do .NET 4.0, Task tornou-se a principal ferramenta para operações assíncronas. Ela abstrai as threads e permite trabalhar com resultados de execução. Exemplo:

using System;using System.Threading.Tasks;

class Program{ static async Task Main() { Task<int> task = Task.Run(() => ComputeResult(10)); // Pode fazer outro trabalho Console.WriteLine("Aguardando resultado..."); int result = await task; Console.WriteLine($"Resultado: {result}"); }

static int ComputeResult(int value) { Task.Delay(1000).Wait(); // Simula uma operação longa return value * 2; }}

Principais vantagens:

  • Retorna resultado via Task<T>
  • Suporta cancelamento via CancellationToken
  • Permite combinar tarefas (ContinueWith, WhenAll, WhenAny)
  • Integrado com async/await


Parallel — para loops paralelos

A classe Parallel simplifica a execução de loops com paralelização. Exemplo:

using System;using System.Threading.Tasks;

class Program{ static void Main()\

Blogs

Book Recommendations