Domanda

Durante la lettura di C # 3.0 in a Nutshell di Joseph e Ben Albahari , mi sono imbattuto nel seguente paragrafo (pagina 673, primo paragrafo sezione intitolata " segnalazione con attesa e di impulso ")

  

"Il Monitor classe fornisce un'altra segnalazione costruire attraverso due metodi statici, Wait e Pulse . Il principio è che si scrive la logica di segnalazione da soli, usando le bandiere personalizzate e campi (racchiuso tra blocco le dichiarazioni), e poi introdurre Attendere e Pulse comandi per mitigare filatura della CPU. Il vantaggio di questo approccio di basso livello è che con solo Attendere , Pulse e blocco dichiarazione, è possibile ottenere la funzionalità del AutoResetEvent , ManualResetEvent e semaforo , così come WaitHandle metodi statici WaitAll e WaitAny . Inoltre, Attendere e Pulse   possono essere suscettibili a situazioni in cui   tutte le maniglie di aspettare sono   parsimonia sfidato ".

La mia domanda è, qual è la corretta interpretazione del ultima frase?

  • Una situazione con un gran numero decente / di attesa gestisce dove WaitOne () è solo occasionalmente invitato una particolare maniglia di attesa.
  • Una situazione con un gran numero decente / di attesa gestisce dove raramente più di un thread tendono a bloccare in un particolare manico di attesa.
  • Qualche altra interpretazione.

Sarebbe inoltre apprezzare esempi illuminanti di tali situazioni e, forse, come e / o perché sono più efficientemente gestite tramite Wait e polso, piuttosto che con altri metodi.

Grazie!

Edit: ho trovato in rete il testo qui

È stato utile?

Soluzione

Quello che sta dicendo è che ci sono alcune situazioni in cui aspettare e impulsi fornisce una soluzione più semplice che aspettare maniglie. In generale, questo avviene dove:

  • Il cameriere, piuttosto che il notificante, decide quando sbloccare
  • La condizione di blocco comporta più di una semplice bandiera (forse più variabili)

È comunque possibile utilizzare attesa gestisce in queste situazioni, ma Wait / Pulse tende ad essere più semplice. La cosa grandiosa di attesa / Pulse è che attendono rilascia il lock sottostante durante l'attesa. Ad esempio, nel seguente esempio, stiamo leggendo _x e _y entro la sicurezza di una serratura - e tuttavia che il blocco viene rilasciato durante l'attesa in modo che un altro thread in grado di aggiornare le variabili:

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

Un altro thread può quindi aggiornare _x e _y atomico (in virtù della serratura) e poi impulso per segnalare il cameriere:

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

Lo svantaggio di attesa / Pulse è che è più facile sbagliare e commettere un errore (per esempio, aggiornando una variabile e dimenticando di Pulse). In situazioni in cui un programma con maniglie attesa è altrettanto semplice per un programma con Wait / Pulse, io consiglierei di andare con maniglie di attesa per questo motivo.

In termini di consumo di efficienza / risorsa (che credo si stava alludendo a), Wait / Pulse è solitamente più veloce e più leggero (in quanto dispone di un'implementazione gestito). Questo è raramente un grosso problema, in pratica, però. E su questo punto, Framework 4.0 include basso overhead gestito versioni di ManualResetEvent e il semaforo (ManualResetEventSlim e SemaphoreSlim).

Framework 4.0 offre anche molte altre opzioni di sincronizzazione che riducono la necessità di attesa / Pulse:

  • CountdownEvent
  • Barriera
  • PLINQ / dati Parallelismo (AsParallel, Parallel.Invoke, Parallel.For, Parallel.ForEach)
  • Compiti e continuazioni

Tutti questi sono di livello superiore più che aspettare / ad impulsi e IMO sono preferibili per la scrittura di codice affidabile e gestibile (ammesso che risolveremo il compito a portata di mano).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top