Resumo : neste tutorial, você aprenderá como usar a CountdownEvent
classe C# para aguardar um número especificado de eventos antes de continuar a execução.
Introdução à classe C# CountdownEvent
O
desbloqueia um thread em espera até receber o número de eventos. Para usar a CountdownEvent
classe, siga estas etapas:CountdownEvent
Primeiro, crie uma nova instância da CountdownEvent
classe, passando um valor de contagem inicial:
var countdownEvent = new CountdownEvent(3);
Linguagem de código: C# ( cs )
Segundo, crie um ou mais threads que sinalizarão um evento. Cada thread precisa chamar o Signal()
método do CountdownEvent
objeto para sinalizar um evento:
// inside a thread
countdownEvent.Signal();
Linguagem de código: C# ( cs )
O Signal()
método diminui a contagem inicial em um.
Terceiro, chame o
método do Wait()
CountdownEvent
objeto nos threads em espera. O
método bloqueará esses threads até que a contagem chegue a zero:Wait()
// on the waiting thread
countdownEvent.Wait();
Linguagem de código: C# ( cs )
Se ocorrer uma exceção que faça com que o Signal()
método não seja chamado, o Wait()
método bloqueará o thread em espera indefinidamente.
Portanto, você deve sempre chamar o Signal()
método mesmo se ocorrer uma exceção.
Além disso, você pode definir um tempo limite para que o Wait()
método desbloqueie o thread em espera se um intervalo de tempo tiver decorrido ou a contagem do CountDownEvent
objeto atingir zero:
countdownEvent.Wait(timeout);
Linguagem de código: C# ( cs )
Por fim, chame o Dispose()
método quando terminar de usar o CountdownEvent
objeto para liberar quaisquer recursos associados a ele:
countdownEvent.Dispose();
Linguagem de código: C# ( cs )
O exemplo a seguir demonstra como a CountdownEvent
classe funciona:
using static System.Console;
var countdownEvent = new CountdownEvent(3);
void DoWork(int id)
{
Thread.Sleep(1000);
WriteLine($"Completed the task {id} ");
countdownEvent.Signal();
}
// create three threads that executes the DoWork
for (int i = 1; i <= 3; i++)
{
var id = i;
var thread = new Thread(() => DoWork(id));
thread.Start();
}
// block the main thread
countdownEvent.Wait();
// execute this once three event has been signaled
Console.WriteLine("All thread completed.");
countdownEvent.Dispose();
Linguagem de código: C# ( cs )
Saída:
Completed the task 2
Completed the task 1
Completed the task 3
All thread completed.
Linguagem de código: C# ( cs )
Como funciona.
Primeiro, crie um novo CountdownEvent
objeto com contagem inicial 3:
var countdownEvent = new CountdownEvent(3);
Linguagem de código: C# ( cs )
Segundo, defina o DoWork()
método que simula uma tarefa que leva um segundo para ser concluída:
void DoWork(int id)
{
Thread.Sleep(1000);
WriteLine($"Completed the task {id} ");
countdownEvent.Signal();
}
Linguagem de código: C# ( cs )
O DoWork()
chama o Signal()
método do CountdownEvent
objeto para diminuir a contagem assim que ela for concluída.
Terceiro, crie três threads que executam o DoWork()
método:
for (int i = 1; i <= 3; i++)
{
var id = i;
var thread = new Thread(() => DoWork(id));
thread.Start();
}
Linguagem de código: C# ( cs )
Quarto, chame o Wait()
método no thread principal para bloqueá-lo até que o CountdownEvent
objeto receba três sinais:
countdownEvent.Wait();
Linguagem de código: C# ( cs )
Quando
chega a zero, é desbloqueado o thread principal que executa o restante do código, escrevendo uma mensagem no console e descartando o CountdownEvent
objeto:CountdownEvent
// execute this once three event has been signaled
Console.WriteLine("All thread completed.");
countdownEvent.Dispose();
Linguagem de código: C# ( cs )
Aplicativos CountdownEvent em C#
Na prática, você pode usar a CountdownEvent
classe nas seguintes aplicações:
- Processamento paralelo: você pode processar um grande conjunto de dados em vários threads e usar um
CountdownEvent
objeto para sincronizar a conclusão de todos os threads antes de prosseguir para a próxima etapa no pipeline de processamento. - Download de arquivos: você pode baixar vários arquivos em paralelo e usar um
CountdownEvent
objeto para esperar até que todos os arquivos sejam baixados antes de processá-los. - Aguardando eventos externos: suponha que seu programa precise aguardar vários eventos externos, como mensagens de rede ou leituras de sensores, antes de prosseguir. Neste caso, você pode usar um
CountdownEvent
objeto para garantir que todos os sinais foram recebidos antes de continuar.
Um exemplo prático da classe C# CountdownEvent
O programa a seguir baixa três arquivos de texto simultaneamente de um servidor remoto e conta as palavras de cada um. Ele usa o CountdownEvent
objeto para aguardar a conclusão dos downloads antes de retornar a contagem total de palavras de três arquivos:
var urls = new List<string>()
{
"https://www.ietf.org/rfc/rfc791.txt",
"https://www.ietf.org/rfc/rfc792.txt",
"https://www.ietf.org/rfc/rfc793.txt"
};
var countDownEvent = new CountdownEvent(urls.Count);
int totalWordCount = 0;
async Task<int> DownloadAndCountWords(string url)
{
Console.WriteLine($"Downloading the file {url}...");
using var client = new HttpClient();
string content = await client.GetStringAsync(url);
Console.WriteLine($"File {url} downloaded.");
int wordCount = CountWords(content);
Console.WriteLine($"Word count of {url}: {wordCount}");
return wordCount;
}
int CountWords(string text)
{
var delimiters = new char[] { ' ', '\r', '\n' };
return text.Split(delimiters, StringSplitOptions.RemoveEmptyEntries).Length;
}
urls.ForEach(url =>
{
Task.Run(async () =>
{
int wordCount = await DownloadAndCountWords(url);
Interlocked.Add(ref totalWordCount, wordCount);
// signal an event
countDownEvent.Signal();
});
});
countDownEvent.Wait(TimeSpan.FromSeconds(3));
countDownEvent.Dispose();
Console.WriteLine($"Total word count: {totalWordCount}");
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
Linguagem de código: C# ( cs )
Saída:
Downloading the file https://www.ietf.org/rfc/rfc791.txt...
Downloading the file https://www.ietf.org/rfc/rfc792.txt...
Downloading the file https://www.ietf.org/rfc/rfc793.txt...
File https://www.ietf.org/rfc/rfc792.txt downloaded.
Word count of https://www.ietf.org/rfc/rfc792.txt: 3714
File https://www.ietf.org/rfc/rfc791.txt downloaded.
Word count of https://www.ietf.org/rfc/rfc791.txt: 11243
File https://www.ietf.org/rfc/rfc793.txt downloaded.
Word count of https://www.ietf.org/rfc/rfc793.txt: 21460
Total word count: 36417
Press any key to exit.
Linguagem de código: C# ( cs )
Resumo
- Use C#
CountdownEvent
para permitir que os threads esperem até que um número especificado de eventos seja sinalizado.