Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A EventWaitHandle classe permite que os threads se comuniquem entre si sinalizando e aguardando sinais. Identificadores de espera de eventos (conhecidos simplesmente como eventos) são identificadores de espera que podem ser sinalizados a fim de liberar um ou mais threads de espera. Após a sinalização, um identificador de espera de eventos é redefinido manualmente ou automaticamente. A EventWaitHandle classe pode representar um identificador de espera de evento local (evento local) ou um identificador de espera de evento do sistema nomeado (evento nomeado ou evento do sistema, visível para todos os processos).
Observação
Os identificadores de espera de eventos não são eventos do .NET. Não há representantes ou manipuladores de eventos envolvidos. A palavra "evento" é usada para descrevê-los porque tradicionalmente são chamados de eventos do sistema operacional e porque o ato de sinalizar o identificador de espera indica aos threads em espera que ocorreu um evento.
Os identificadores de espera de eventos local e nomeado usam objetos de sincronização do sistema, que são protegidos por wrappers SafeWaitHandle a fim de garantir a liberação de recursos. Você pode usar o Dispose método para liberar os recursos imediatamente quando terminar de usar o objeto.
Identificadores de espera de eventos redefinidos automaticamente
Crie um evento de redefinição automática especificando EventResetMode.AutoReset ao criar o objeto EventWaitHandle. Como o nome sugere, esse evento de sincronização é redefinido automaticamente quando sinalizado, após a liberação de um thread de espera único. Sinalize o evento chamando seu Set método.
Os eventos de redefinição automática geralmente são usados para fornecer acesso exclusivo a um recurso para um thread por vez. Um thread solicita o recurso chamando o WaitOne método. Se nenhum outro thread estiver segurando o identificador de espera, o método retornará true e o thread de chamada terá controle do recurso.
Importante
Assim como acontece com todos os mecanismos de sincronização, você deve garantir que todas as linhas de código esperem no identificador de espera correto antes de acessar um recurso protegido. A sincronização de threads é cooperativa.
Se um evento de redefinição automática for sinalizado quando não houver threads em espera, ele permanecerá sinalizado até que um thread tente esperar por ele. O evento libera o thread e redefine imediatamente, bloqueando os threads subsequentes.
Identificadores de espera de evento redefinidos automaticamente
Você cria um evento de redefinição manual especificando EventResetMode.ManualReset quando cria o EventWaitHandle objeto. Como o nome indica, esse evento de sincronização deve ser redefinido manualmente depois de ter sido sinalizado. Até a redefinição, ao chamar seu método Reset, os threads que aguardam o identificador de evento continuam imediatamente sem bloqueio.
Um evento de redefinição manual age como a porta de um curral. Quando o evento não é sinalizado, os threads que aguardam por ele ficam bloqueados, como cavalos em um curral. Quando o evento é sinalizado, ao chamar seu método Set, todos os threads em espera ficam livres para continuar. O evento permanece sinalizado até que seu Reset método seja chamado. Isso torna o evento de redefinição manual a maneira ideal de armazenar threads que precisam aguardar até que um thread conclua uma tarefa.
Como cavalos deixando um curral, demora até o sistema operacional agendar os threads liberados e continuar a execução. Se o Reset método for chamado antes de todos os threads retomarem a execução, os threads restantes serão bloqueados novamente. Os threads que retomam a operação e os threads que são bloqueados depende de fatores aleatórios, como a carga no sistema, o número de threads aguardando o agendador etc. Isso não será um problema se o thread que sinaliza o evento terminar após a sinalização, que é o padrão de uso mais comum. Se você quiser que o thread que sinalizou o evento inicie uma nova tarefa depois que todos os threads de espera forem retomados, você deverá bloqueá-lo até que todos os threads de espera sejam retomados. Caso contrário, você terá uma condição de corrida, e o comportamento do seu código será imprevisível.
Recursos comuns a eventos automáticos e manuais
Normalmente, um ou mais threads ficam bloqueados em um EventWaitHandle até que um thread desbloqueado chame o método Set, o que libera um dos threads em espera (no caso de eventos de redefinição automática) ou todos eles (no caso de eventos de redefinição manual). Um thread pode sinalizar um EventWaitHandle e depois bloqueá-lo, como uma operação atômica, chamando o método WaitHandle.SignalAndWait estático.
Os EventWaitHandle objetos podem ser usados com os métodos estáticos WaitHandle.WaitAll e WaitHandle.WaitAny. Como as classes EventWaitHandle e Mutex derivam de WaitHandle, você pode usar ambas as classes com esses métodos.
Eventos nomeados
O sistema operacional Windows permite que os identificadores de espera de eventos tenham nomes. Um evento nomeado serve para todo o sistema. Ou seja, depois que o evento nomeado é criado, ele fica visível para todos os threads em todos os processos. Assim, os eventos nomeados podem ser usados para sincronizar as atividades de processos e threads.
Você pode criar um EventWaitHandle objeto que representa um evento de sistema nomeado usando um dos construtores que especifica um nome de evento.
Observação
Como os eventos nomeados são de todo o sistema, é possível ter vários EventWaitHandle objetos que representam o mesmo evento nomeado. Cada vez que você chama um construtor ou o OpenExisting método, um novo EventWaitHandle objeto é criado. Especificar o mesmo nome cria repetidamente vários objetos que representam o mesmo evento nomeado.
É aconselhado ter cautela ao usar eventos nomeados. Como eles servem para todo o sistema, outro processo que usa o mesmo nome pode bloquear seus threads inesperadamente. A execução de código mal-intencionado no mesmo computador pode usar isso como base de um ataque de negação de serviço.
Use a segurança do controle de acesso para proteger um EventWaitHandle objeto que representa um evento nomeado, preferencialmente usando um construtor que especifica um EventWaitHandleSecurity objeto. Você também pode aplicar a segurança do controle de acesso usando o SetAccessControl método, mas isso deixa uma janela de vulnerabilidade entre o momento em que o identificador de espera do evento é criado e a hora em que ele está protegido. Proteger eventos com controle de acesso de segurança ajuda a evitar ataques mal-intencionados, mas não resolve o problema de colisões de nomes não intencionais.
Observação
Ao contrário da EventWaitHandle classe, as classes AutoResetEvent derivadas e ManualResetEvent podem representar apenas identificadores de espera locais. Eles não podem representar eventos nomeados do sistema.