Pergunta

Enquanto lê C# 3.0 em poucas palavras por Joseph e Ben Albahari, Me deparei com o parágrafo seguinte (página 673, primeiro parágrafo na seção intitulado "Sinalização com espera e pulso")

"O Monitor A classe fornece outra construção de sinalização por meio de dois métodos estáticos, Espere e Pulso. O princípio é que você escreve a lógica de sinalização usando sinalizadores e campos personalizados (fechados em trancar declarações) e depois apresentar Espere e Pulso comandos para mitigar a fiação da CPU. A vantagem dessa abordagem de baixo nível é que apenas com Espere, Pulso, e as trancar declaração, você pode alcançar a funcionalidade de AUTORESETEVENT, ManualResetevent, e Semáforo, assim como WaitHandleMétodos estáticos Espera e Espera. Além disso, Espere e Pulsopode ser passível de passageira em situações em que todas as alças de espera são desafiadas parcimoniosamente ".

Minha pergunta é: qual é a interpretação correta do último frase?

  • Uma situação com um número decente/grande de alças de espera, onde o Wagone () é apenas ocasionalmente chamado em qualquer alça de espera específica.
  • Uma situação com um número decente/grande de alças de espera, onde raramente faz mais de um fio tende a bloquear em qualquer alça de espera específica.
  • Alguma outra interpretação.

Também apreciaria exemplos esclarecedores de tais situações e talvez como e/ou por que eles são tratados com mais eficiência por meio de espera e pulso, e não por outros métodos.

Obrigada!

EDIT: Encontrei o texto online aqui

Foi útil?

Solução

O que isso está dizendo é que existem algumas situações em que a espera e o pulso fornecem uma solução mais simples do que as alças de espera. Em geral, isso acontece onde:

  • O garçom, em vez do notificador, decide quando desbloquear
  • A condição de bloqueio envolve mais do que uma bandeira simples (talvez várias variáveis)

Você ainda pode usar alças de espera nessas situações, mas o Wait/Pulse tende a ser mais simples. O melhor de Wait/Pulse é que a espera libera a fechadura subjacente enquanto espera. Por exemplo, no exemplo a seguir, estamos lendo _x e _y na segurança de um bloqueio - e, no entanto, esse bloqueio é liberado enquanto espera para que outro tópico possa atualizar essas variáveis:

lock (_locker)
{
  while (_x < 10 && _y < 20) Monitor.Wait (_locker);
}

Outro tópico pode atualizar _x e _y atomicamente (em virtude da trava) e depois pulsar para sinalizar o garçom:

lock (_locker)
{
  _x = 20;
  _y = 30;
  Monitor.Pulse (_locker);
} 

A desvantagem da espera/pulso é que é mais fácil errar e cometer um erro (por exemplo, atualizando uma variável e esquecendo de pulsar). Em situações em que um programa com alças de espera é igualmente simples para um programa com espera/pulso, eu recomendo ir com alças de espera por esse motivo.

Em termos de eficiência/consumo de recursos (que eu acho que você estava aludindo), o Wait/Pulse geralmente é mais rápido e mais leve (pois possui uma implementação gerenciada). Isso raramente é um grande negócio na prática, no entanto. E nesse ponto, o Framework 4.0 inclui versões gerenciadas de baixa sobrecarga de manualresetevent e semáforo (manualreteventslim e semáforeslim).

O Framework 4.0 também fornece muito mais opções de sincronização que diminuem a necessidade de espera/pulso:

  • CountdownEvent
  • Barreira
  • Paralelismo de plinq / dados (asparalelos, paralelos.invoke, paralelo. para, paralelo.foreach)
  • Tarefas e continuações

Tudo isso é muito mais alto que o Wait/Pulse e a IMO é preferível para escrever código confiável e sustentável (supondo que eles resolvam a tarefa em questão).

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