Evento de contagem regressiva C#

Resumo : neste tutorial, você aprenderá como usar a CountdownEventclasse C# para aguardar um número especificado de eventos antes de continuar a execução.

Introdução à classe C# CountdownEvent

O CountdownEventdesbloqueia um thread em espera até receber o número de eventos. Para usar a CountdownEventclasse, siga estas etapas:

Primeiro, crie uma nova instância da CountdownEventclasse, 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 CountdownEventobjeto 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 Wait()método do CountdownEventobjeto nos threads em espera. O Wait()método bloqueará esses threads até que a contagem chegue a zero:

// 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 CountDownEventobjeto atingir zero:

countdownEvent.Wait(timeout);Linguagem de código:  C#  ( cs )

Por fim, chame o Dispose()método quando terminar de usar o CountdownEventobjeto para liberar quaisquer recursos associados a ele:

countdownEvent.Dispose();Linguagem de código:  C#  ( cs )

O exemplo a seguir demonstra como a CountdownEventclasse 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 CountdownEventobjeto 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 CountdownEventobjeto 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 CountdownEventobjeto receba três sinais:

countdownEvent.Wait();Linguagem de código:  C#  ( cs )

Quando CountdownEventchega a zero, é desbloqueado o thread principal que executa o restante do código, escrevendo uma mensagem no console e descartando o CountdownEventobjeto:

// 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 CountdownEventclasse nas seguintes aplicações:

  • Processamento paralelo: você pode processar um grande conjunto de dados em vários threads e usar um CountdownEventobjeto 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 CountdownEventobjeto 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 CountdownEventobjeto 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 CountdownEventobjeto 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# CountdownEventpara permitir que os threads esperem até que um número especificado de eventos seja sinalizado.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *