Pergunta

Eu li a documentação sobre isso e eu acho que entendo. Um AutoResetEvent redefine quando o código passa por event.WaitOne(), mas um ManualResetEvent não.

É este correto?

Foi útil?

Solução

Sim. É como a diferença entre um pedágio e uma porta. O ManualResetEvent é a porta, o qual necessita de ser fechada (reset) manualmente. O AutoResetEvent é um pedágio, permitindo que um carro para ir por e automaticamente fechar antes que o próximo pode passar.

Outras dicas

Basta imaginar que executa a AutoResetEvent WaitOne() e Reset() como uma única operação atômica.

A resposta curta é sim. A diferença mais importante é que uma AutoResetEvent só irá permitir que um único segmento de espera para continuar. A ManualResetEvent por outro lado vai manter permitindo threads, vários ao mesmo tempo, mesmo, para continuar até que você diga a ele para parar (Reset-lo).

Tomado de C # 3.0 Nutshell livro, por Joseph Albahari

Enfiar em C # - Free E-Book

A ManualResetEvent é uma variação sobre AutoResetEvent. Ela difere em que ele não reiniciar automaticamente depois que um segmento é deixar passar em uma chamada WaitOne, e assim funciona como um portão: chamando Set abre o portão, permitindo que qualquer número de segmentos que WaitOne no portão através; chamando Repor fecha a porta, fazendo com que, potencialmente, uma fila de garçons a acumular-se até ao seu lado aberto.

Pode-se simular esta funcionalidade com um boolean campo "gateOpen" (declarado com a palavra-chave volátil) em combinação com "spin-dormir." - repetidamente verificando a bandeira, e depois dormir por um curto período de tempo

ManualResetEvents são por vezes usados ??para sinalizar que uma determinada operação for concluída, ou que um fio de concluída a inicialização e está pronto para executar o trabalho.

Eu criei exemplos simples para esclarecer o entendimento de ManualResetEvent vs AutoResetEvent.

AutoResetEvent: vamos supor que você tem fios 3 trabalhadores. Se qualquer um desses tópicos será chamada WaitOne() todos os outros 2 fios irá parar a execução e esperar por sinal. Estou assumindo que eles estão usando WaitOne(). É como; se eu não trabalho, ninguém trabalha. No primeiro exemplo você pode ver que

autoReset.Set();
Thread.Sleep(1000);
autoReset.Set();

Quando você chama Set() os tópicos vai trabalhar e esperar por sinal. Após 1 segundo, estou enviando segundo sinal e eles executar e espera (WaitOne()). Pense sobre esses caras são jogadores da equipe de futebol e se um jogador diz que vai esperar até gerente me chama, e os outros vão esperar até gerente diz-lhes para continuar (Set())

public class AutoResetEventSample
{
    private AutoResetEvent autoReset = new AutoResetEvent(false);

    public void RunAll()
    {
        new Thread(Worker1).Start();
        new Thread(Worker2).Start();
        new Thread(Worker3).Start();
        autoReset.Set();
        Thread.Sleep(1000);
        autoReset.Set();
        Console.WriteLine("Main thread reached to end.");
    }

    public void Worker1()
    {
        Console.WriteLine("Entered in worker 1");
        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker1 is running {0}", i);
            Thread.Sleep(2000);
            autoReset.WaitOne();
        }
    }
    public void Worker2()
    {
        Console.WriteLine("Entered in worker 2");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker2 is running {0}", i);
            Thread.Sleep(2000);
            autoReset.WaitOne();
        }
    }
    public void Worker3()
    {
        Console.WriteLine("Entered in worker 3");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker3 is running {0}", i);
            Thread.Sleep(2000);
            autoReset.WaitOne();
        }
    }
}

Neste exemplo você pode ver claramente que quando você primeiro Set() hit ele vai deixar os tópicos ir, em seguida, depois de 1 segundo ele sinaliza os tópicos para esperar! Assim que você configurá-los novamente, independentemente eles estão chamando WaitOne() dentro, eles vão continuar correndo porque você tem que Reset() chamada manualmente para detê-los todos.

manualReset.Set();
Thread.Sleep(1000);
manualReset.Reset();
Console.WriteLine("Press to release all threads.");
Console.ReadLine();
manualReset.Set();

É mais sobre Árbitro / relacionamento Jogadores lá independentemente de qualquer do jogador está lesionado e esperar para jogar os outros vão continuar a trabalhar. Se Árbitro diz wait (Reset()), em seguida, todos os jogadores vão esperar até o próximo sinal.

public class ManualResetEventSample
{
    private ManualResetEvent manualReset = new ManualResetEvent(false);

    public void RunAll()
    {
        new Thread(Worker1).Start();
        new Thread(Worker2).Start();
        new Thread(Worker3).Start();
        manualReset.Set();
        Thread.Sleep(1000);
        manualReset.Reset();
        Console.WriteLine("Press to release all threads.");
        Console.ReadLine();
        manualReset.Set();
        Console.WriteLine("Main thread reached to end.");
    }

    public void Worker1()
    {
        Console.WriteLine("Entered in worker 1");
        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker1 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
    public void Worker2()
    {
        Console.WriteLine("Entered in worker 2");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker2 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
    public void Worker3()
    {
        Console.WriteLine("Entered in worker 3");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker3 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
}

autoResetEvent.WaitOne()

é semelhante ao

try
{
   manualResetEvent.WaitOne();
}
finally
{
   manualResetEvent.Reset();
}

como uma operação atômica

OK, normalmente não uma boa prática de adicionar 2 respostas na mesma linha, mas eu não queria editar / apagar a minha resposta anterior, uma vez que pode ajudar em outra forma.

Agora, eu criei, muito mais abrangente e fácil de entender, run-to-aprender console app trecho abaixo.

Apenas executar os exemplos em dois consoles diferentes e observar o comportamento. Você vai ter muito mais clara ideia de que o que está acontecendo nos bastidores.

Manual Redefinir Evento

using System;
using System.Threading;

namespace ConsoleApplicationDotNetBasics.ThreadingExamples
{
    public class ManualResetEventSample
    {
        private readonly ManualResetEvent _manualReset = new ManualResetEvent(false);

        public void RunAll()
        {
            new Thread(Worker1).Start();
            new Thread(Worker2).Start();
            new Thread(Worker3).Start();
            Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below.");
            Thread.Sleep(15000);
            Console.WriteLine("1- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("2- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("3- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("4- Main will call ManualResetEvent.Reset() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Reset();
            Thread.Sleep(2000);
            Console.WriteLine("It ran one more time. Why? Even Reset Sets the state of the event to nonsignaled (false), causing threads to block, this will initial the state, and threads will run again until they WaitOne().");
            Thread.Sleep(10000);
            Console.WriteLine();
            Console.WriteLine("This will go so on. Everytime you call Set(), ManualResetEvent will let ALL threads to run. So if you want synchronization between them, consider using AutoReset event, or simply user TPL (Task Parallel Library).");
            Thread.Sleep(5000);
            Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);

        }

        public void Worker1()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker1 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker2()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker2 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker3()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker3 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
    }

}

 manual de reset desta saída Event

Auto Repor Evento

using System;
using System.Threading;

namespace ConsoleApplicationDotNetBasics.ThreadingExamples
{
    public class AutoResetEventSample
    {
        private readonly AutoResetEvent _autoReset = new AutoResetEvent(false);

        public void RunAll()
        {
            new Thread(Worker1).Start();
            new Thread(Worker2).Start();
            new Thread(Worker3).Start();
            Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below.");
            Thread.Sleep(15000);
            Console.WriteLine("1- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("2- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("3- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("4- Main will call AutoResetEvent.Reset() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Reset();
            Thread.Sleep(2000);
            Console.WriteLine("Nothing happened. Why? Becasuse Reset Sets the state of the event to nonsignaled, causing threads to block. Since they are already blocked, it will not affect anything.");
            Thread.Sleep(10000);
            Console.WriteLine("This will go so on. Everytime you call Set(), AutoResetEvent will let another thread to run. It will make it automatically, so you do not need to worry about thread running order, unless you want it manually!");
            Thread.Sleep(5000);
            Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);

        }

        public void Worker1()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker1 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker2()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker2 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker3()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker3 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
    }

}

 Auto de saída Repor evento

Sim. Isso é absolutamente correto.

Você pode ver ManualResetEvent como uma maneira de indicar o estado. Algo está ligado (Set) ou off (Reset). Uma ocorrência com algum duração. Qualquer segmento de espera para esse estado a acontecer pode prosseguir.

Um AutoResetEvent é mais comparável a um sinal. A indicação de um tiro que algo aconteceu. Uma ocorrência sem qualquer duração. Normalmente, mas não necessariamente o "algo" que aconteceu é pequeno e precisa ser tratada por um único segmento - daí o rearme automático após um único segmento ter consumido o evento.

Sim, isso é certo.

Você pode ter uma idéia do uso destes dois.

Se você precisa dizer que você terminar com algum trabalho e outros (threads) esperando por isso pode agora avançar, você deve usar ManualResetEvent.

Se você precisa ter acesso exclusivo mútua a qualquer recurso, você deve usar AutoResetEvent.

AutoResetEvent mantém uma variável booleana na memória. Se a variável booleana é falsa, então ele bloqueia o fio e se a variável boolean é verdade que desbloqueia o segmento.

Quando instanciar um objeto AutoResetEvent, passamos o valor padrão de valor booleano no construtor. Abaixo está a sintaxe de instanciar um objeto AutoResetEvent.

AutoResetEvent autoResetEvent = new AutoResetEvent(false);

método WaitOne

Este método bloqueia o segmento atual e aguarde o sinal de outro segmento. WaitOne método coloca o atual segmento em um estado do segmento de suspensão. WaitOne método retorna true se ele recebe o sinal senão retorna falso.

autoResetEvent.WaitOne();

Segundo sobrecarga de WaitOne espera método para o número especificado de segundos. Se ele não recebe qualquer tópico sinal continua o seu trabalho.

static void ThreadMethod()
{
    while(!autoResetEvent.WaitOne(TimeSpan.FromSeconds(2)))
    {
        Console.WriteLine("Continue");
        Thread.Sleep(TimeSpan.FromSeconds(1));
    }

    Console.WriteLine("Thread got signal");
}

Nós chamado método WaitOne passando os 2 segundos como argumentos. No loop while, é aguardar o sinal por 2 segundos, em seguida, continua o seu trabalho. Quando o segmento tem os WaitOne sinal retorna verdadeiro e sai do loop e imprimir o "fio de sinal tem".

método Set

método AutoResetEvent Set enviou o sinal para o segmento de espera para continuar o seu trabalho. Abaixo está a sintaxe de chamar o método Set.

autoResetEvent.Set();

ManualResetEvent mantém uma variável booleana na memória. Quando a variável booleana é falsa, então ele bloqueia os tópicos e quando a variável booleana é verdade que desbloqueia os tópicos.

Quando instanciar um ManualResetEvent, nós inicialize-o com padrão valor booleano.

ManualResetEvent manualResetEvent = new ManualResetEvent(false);

No código acima, nós inicializar o ManualResetEvent com valor falso, isso significa que todos os segmentos que chama o método WaitOne irá bloquear até que algum thread chama o método set ().

Se inicializar ManualResetEvent com verdadeiro valor, todos os tópicos que chama o método WaitOne não vai bloquear e livre para prosseguir.

Método WaitOne

Este método bloqueia o segmento atual e aguarde o sinal de outro segmento. Ele retorna verdadeiro se a sua recebe um sinal senão retorna falso.

A seguir é a sintaxe de chamar método WaitOne.

manualResetEvent.WaitOne();

Na segunda sobrecarga do método WaitOne, podemos especificar o intervalo de tempo até a espera thread atual para o sinal. Se dentro do tempo interno, ele não recebe um sinal que retorna falso e vai para a próxima linha de método.

A seguir é a sintaxe de chamar método WaitOne com intervalo de tempo.

bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));

Temos especificar 5 segundos para o método WaitOne. Se o objeto ManualResetEvent não recebe um sinal entre 5 segundos, é definir a variável isSignalled como falsa.

Set Método

Este método é usado para enviar o sinal para todos os segmentos de espera. Set () Método de definir a variável boolean ManualResetEvent objeto para true. Todos os segmentos de espera são desbloqueados e prosseguir.

A seguir é a sintaxe de chamar Set () método.

manualResetEvent.Set();

Redefinir Método

Uma vez que chamar o método set () no objeto ManualResetEvent, seus boolean permanece fiel. Para repor o valor que pode usar o método Reset (). Redefinir método mudança o valor booleano como falsa.

A seguir é a sintaxe de chamar Reset método.

manualResetEvent.Reset();

Nós deve chamar imediatamente Reset método depois de chamar o método set, se quisermos enviar sinal para tópicos várias vezes.

Se você quiser entender AutoResetEvent e ManualResetEvent você precisa entender não enfiar mas interrupções!

.NET quer evocar baixo nível de programação o mais distante possível.

Um interrupções é algo usado em programação de baixo nível que equivale a um sinal de que a partir de baixo tornou-se alta (ou vice-versa). Quando isso acontece, o programa de interrupção a sua execução normal e mover o ponteiro de execução para a função que lida com esta evento .

A primeira coisa a fazer quando um happend interrupção é reset o seu estado, becosa o hardware funciona desta maneira:

  1. um pino é conectado a um sinal eo hardware ouvir para que a mudança (o sinal poderia ter apenas dois estados).
  2. Se o sinal muda significa que algo aconteceu eo hardware colocar uma variável memória para o estado aconteceu (e continuar assim mesmo se a mudança de sinal de novo).
  3. o aviso de programa que estados e mudanças de variáveis ??mover a execução para uma função de manipulação.
  4. aqui a primeira coisa a fazer, para ser capaz de ouvir de novo esta interrupção, é reset esta variável de memória para o estado não-acontecido.

Esta é a diferença entre ManualResetEvent e AutoResetEvent.
Se um ManualResetEvent acontecer e eu não redefini-la, a próxima vez que isso acontece eu não será capaz de ouvir isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top