Eu li a documentação sobre isso e acho que entendo. Um AutoResetEvent
redefine quando o código passa event.WaitOne()
, mas um ManualResetEvent
não.
Isso está correto?
c#
.net
multithreading
autoresetevent
manualresetevent
Ben McNiel
fonte
fonte
Respostas:
Sim. É como a diferença entre pedágio e porta. A
ManualResetEvent
é a porta, o qual necessita de ser fechada (reset) manualmente. OAutoResetEvent
é um pedágio, permitindo que um carro passe e feche automaticamente antes que o próximo possa passar.fonte
Imagine que o
AutoResetEvent
executaWaitOne()
eReset()
como uma única operação atômica.fonte
A resposta curta é sim. A diferença mais importante é que um AutoResetEvent permitirá apenas que um único thread em espera continue. Um ManualResetEvent, por outro lado, continuará permitindo que os threads, vários ao mesmo tempo, continuem até que você peça para parar (Redefina-o).
fonte
Encadeamento em C # - E-Book Gratuito
Um ManualResetEvent é uma variação do AutoResetEvent. Ele difere por não ser redefinido automaticamente depois que um thread é liberado em uma chamada do WaitOne e funciona como um gate: o chamado Set abre o gate, permitindo qualquer número de threads que o WaitOne passa no gate; ligar para Reset fecha o portão, fazendo com que, potencialmente, uma fila de garçons se acumule até a próxima abertura.
Pode-se simular essa funcionalidade com um campo booleano "gateOpen" (declarado com a palavra-chave volátil) em combinação com "spin-sleeping" - verificando repetidamente o sinalizador e depois inativo por um curto período de tempo.
Às vezes, ManualResetEvents são usados para sinalizar que uma operação específica está concluída ou que a inicialização concluída de um encadeamento e está pronta para executar o trabalho.
fonte
Eu criei exemplos simples para esclarecer a compreensão da
ManualResetEvent
vsAutoResetEvent
.AutoResetEvent
: vamos supor que você tenha 3 linhas de trabalho. Se qualquer um desses threads chamarWaitOne()
todos os outros 2 threads, interromperá a execução e aguardará o sinal. Estou assumindo que eles estão usandoWaitOne()
. É como; se eu não trabalhar, ninguém trabalha. No primeiro exemplo, você pode ver queQuando você liga,
Set()
todos os threads funcionam e aguardam o sinal. Após 1 segundo, estou enviando o segundo sinal e eles executam e aguardam (WaitOne()
). Pense que esses caras são jogadores de times de futebol e, se um jogador disser que vou esperar até o gerente me ligar, e outros vão esperar até o gerente pedir para eles continuarem (Set()
)Neste exemplo, você pode ver claramente que, quando você pressiona pela primeira
Set()
vez, todos os threads desaparecem e, após 1 segundo, sinaliza para que todos os threads aguardem! Assim que você configurá-los novamente, independentemente de estarem ligando paraWaitOne()
dentro, eles continuarão funcionando, pois é necessário ligar manualmenteReset()
para interromper todos eles.É mais sobre a relação entre Árbitro / Jogador, independentemente de qualquer jogador estar ferido e esperar que outros jogadores continuem trabalhando. Se o Árbitro disser esperar (
Reset()
), todos os jogadores aguardarão até o próximo sinal.fonte
autoResetEvent.WaitOne()
é similar a
como uma operação atômica
fonte
OK, normalmente não é uma boa prática adicionar 2 respostas no mesmo segmento, mas eu não queria editar / excluir minha resposta anterior, pois ela pode ajudar de outra maneira.
Agora, criei, abaixo, um snippet de aplicativo de console muito mais abrangente e fácil de entender.
Apenas execute os exemplos em dois consoles diferentes e observe o comportamento. Você terá uma idéia muito mais clara do que está acontecendo nos bastidores.
Evento de redefinição manual
Evento de redefinição automática
fonte
AutoResetEvent mantém uma variável booleana na memória. Se a variável booleana for falsa, ela bloqueia o encadeamento e, se a variável booleana for verdadeira, ela desbloqueia o encadeamento.
Quando instanciamos um objeto AutoResetEvent, passamos o valor padrão do valor booleano no construtor. Abaixo está a sintaxe de instanciar um objeto AutoResetEvent.
Método WaitOne
Este método bloqueia o segmento atual e aguarda o sinal por outro segmento. O método WaitOne coloca o thread atual em um estado de suspensão do thread. O método WaitOne retorna true se receber o sinal, caso contrário, retorna false.
A segunda sobrecarga do método WaitOne aguarda o número especificado de segundos. Se ele não receber nenhum segmento de sinal, continua seu trabalho.
Chamamos o método WaitOne passando os 2 segundos como argumentos. No loop while, aguarda o sinal por 2 segundos e continua seu trabalho. Quando o thread recebe o sinal, o WaitOne retorna true, sai do loop e imprime o "Thread got signal".
Definir método
O método AutoResetEvent Set enviou o sinal para o thread em espera para continuar seu trabalho. Abaixo está a sintaxe de chamar o método Set.
ManualResetEvent mantém uma variável booleana na memória. Quando a variável booleana é falsa, ela bloqueia todos os segmentos e, quando a variável booleana é verdadeira, desbloqueia todos os segmentos.
Quando instanciamos um ManualResetEvent, inicializamos com o valor booleano padrão.
No código acima, inicializamos o ManualResetEvent com valor falso, ou seja, todos os threads que chamam o método WaitOne serão bloqueados até que algum thread chame o método Set ().
Se inicializarmos ManualResetEvent com valor verdadeiro, todos os threads que chamam o método WaitOne não serão bloqueados e liberados para prosseguir.
Método WaitOne
Este método bloqueia o segmento atual e aguarda o sinal por outro segmento. Retorna true se receber um sinal, caso contrário, retornará false.
Abaixo está a sintaxe de chamar o método WaitOne.
Na segunda sobrecarga do método WaitOne, podemos especificar o intervalo de tempo até o encadeamento atual aguardar o sinal. Se dentro do tempo interno, ele não recebe um sinal, retorna falso e passa para a próxima linha de método.
Abaixo está a sintaxe de chamar o método WaitOne com intervalo de tempo.
Nós especificamos 5 segundos no método WaitOne. Se o objeto manualResetEvent não receber um sinal entre 5 segundos, defina a variável isSignalled como false.
Método Set
Este método é usado para enviar o sinal para todos os threads em espera. Método Set () defina a variável booleana do objeto ManualResetEvent como true. Todos os threads em espera são desbloqueados e prosseguem.
Abaixo está a sintaxe de chamar o método Set ().
Método de redefinição
Depois que chamamos o método Set () no objeto ManualResetEvent, seu booleano permanece verdadeiro. Para redefinir o valor, podemos usar o método Reset (). Redefinir método altere o valor booleano para false.
Abaixo está a sintaxe de chamar o método Reset.
Devemos chamar imediatamente o método Reset depois de chamar o método Set, se queremos enviar sinal para threads várias vezes.
fonte
Sim. Isto está absolutamente correto.
Você pode ver ManualResetEvent como uma maneira de indicar o estado. Algo está ativado (definido) ou desativado (redefinido). Uma ocorrência com alguma duração. Qualquer thread que aguarde esse estado pode continuar.
Um AutoResetEvent é mais comparável a um sinal. Uma indicação instantânea de que algo aconteceu. Uma ocorrência sem qualquer duração. Normalmente, mas não necessariamente, o "algo" que aconteceu é pequeno e precisa ser tratado por um único thread - portanto, a redefinição automática após um único thread consumir o evento.
fonte
Sim está certo.
Você pode ter uma idéia usando esses dois.
Se você precisar informar que concluiu algum trabalho e outros (threads) aguardando isso agora podem continuar, use ManualResetEvent.
Se você precisar ter acesso exclusivo mútuo a qualquer recurso, use o AutoResetEvent.
fonte
Se você quiser entender AutoResetEvent e ManualResetEvent, precisará entender não o encadeamento, mas as interrupções!
O .NET quer conjurar a programação de baixo nível o mais distante possível.
Uma interrupção é algo usado na programação de baixo nível que é igual a um sinal que de baixo se tornou alto (ou vice-versa). Quando isso acontece, o programa interrompe sua execução normal e move o ponteiro de execução para a função que manipula esse evento .
A primeira coisa a fazer quando ocorre uma interrupção é redefinir seu estado, porque o hardware funciona desta maneira:
Essa é a diferença entre ManualResetEvent e AutoResetEvent.
Se um ManualResetEvent acontecer e eu não o redefinir, da próxima vez que acontecer, não poderei ouvi-lo.
fonte