2009-12-31 8 views
8

¿Están las variables de condición & monitores utilizados en C#?Variables de condición en C#

¿Alguien me puede dar un ejemplo?

+2

Así como el bloqueo de declaración y la clase del monitor, echar un vistazo a WaitHandles (http://msdn.microsoft.com/en-us/library/system.threading.waithandle.aspx) que puede ser muy útil y salvarte de aburrido repetitivo. – Skurmedel

Respuesta

12

El equivalente de una condición variable que se utiliza sólo para la señalización en .NET es la clase WaitHandle abstracto. Implementaciones prácticas de él son las clases ManualResetEvent y AutoResetEvent.

Una variable de condición que utilice como monitor requiere System.Threading.Monitor. La instrucción C# lock hace que sea muy fácil de usar, asegura que el monitor siempre salga sin programar explícitamente la llamada Exit().

+2

Tenga en cuenta que salir de un monitor si el código arroja una excepción no es necesariamente algo bueno; el monitor probablemente estaba protegiendo una mutación para garantizar que el resultado al salir del monitor fuera consistente; una excepción es evidencia de que la mutación se completó solo parcialmente y, por lo tanto, acaba de desbloquear el acceso al estado incoherente. Si se captura la excepción y el programa continúa, entonces no puede confiar en que el estado del programa sea consistente. –

+0

Muy buen punto, volví a redactar eso. Gracias. –

+5

Espera (perdón por el juego de palabras). ¿Alguno de esos es realmente un equivalente directo de una variable de condición? Para mi ojo no experto, no se parecen en nada a una variable de condición. De hecho he visto una página web que muestra cómo construir una variable de condición de los objetos del núcleo de Windows como eventos de auto-reset, y es un proceso bastante complejo que implica más de un núcleo de tales objetos ... – mackenir

3

Puede usar el objeto Lock que actúa como azúcar sintáctico para la clase Monitor.

lock(someObject) 
{ 
    // Thread safe code here. 
} 

http://msdn.microsoft.com/en-us/library/c5kehkcz%28VS.80%29.aspx

+3

Una pequeña corrección, no es un objeto, sino una palabra clave, y se escribe en minúscula, 'lock' :) – Skurmedel

+0

Gracias, he estado desarrollando en VB.NET en el trabajo, así que tenía SyncLock en el cerebro y simplemente eliminé la parte Sync heh . –

2

Como alternativa a ManualResetEvent y sus amigos, Windows ahora proporciona native support para las variables de condición. No he realizado una evaluación comparativa yo mismo, pero hay muchas posibilidades de que mejore su rendimiento al aprovechar la API nativa.

Aquí es un artículo de código del proyecto que explica cómo acceder a esta (relativamente nuevo) construir a partir de C#:

A .NET Wrapper for the Vista/Server 2008 Condition Variable

0

Esta versión desbloquea atómicamente un mutex o ReaderWriterLockSlim a la espera de señalización, y vuelve a cerrar antes de volver - que es la forma posix.

using System.Collections.Concurrent; 

namespace System.Threading.More { 
    public class ConditionVariable { 
     private readonly ConcurrentQueue<ManualResetEventSlim> _waitingThreads = new ConcurrentQueue<ManualResetEventSlim>(); 

     /// <summary> 
     ///  Atomically unlocks and waits for a signal. 
     ///  Then relocks the mutex before returning 
     /// </summary> 
     /// <param name="mutex"></param> 
     public void Wait(Mutex mutex) { 
      if (mutex == null) { 
       throw new ArgumentNullException("mutex"); 
      } 
      var waitHandle = new ManualResetEventSlim(); 
      try { 
       _waitingThreads.Enqueue(waitHandle); 
       mutex.ReleaseMutex(); 
       waitHandle.Wait(); 
      } finally { 
       waitHandle.Dispose(); 
      } 
      mutex.WaitOne(); 
     } 

     public void WaitRead(ReaderWriterLockSlim readerWriterLock) { 
      if (readerWriterLock == null) { 
       throw new ArgumentNullException("readerWriterLock"); 
      } 
      var waitHandle = new ManualResetEventSlim(); 
      try { 
       _waitingThreads.Enqueue(waitHandle); 
       readerWriterLock.ExitReadLock(); 
       waitHandle.Wait(); 
      } finally { 
       waitHandle.Dispose(); 
      } 
      readerWriterLock.EnterReadLock(); 
     } 

     public void Signal() { 
      ManualResetEventSlim waitHandle; 
      if (_waitingThreads.TryDequeue(out waitHandle)) { 
       waitHandle.Set(); 
      } 
     } 

     public void Broadcast() { 
      ManualResetEventSlim waitHandle; 
      while (_waitingThreads.TryDequeue(out waitHandle)) { 
       waitHandle.Set(); 
      } 
     } 
    } 
} 
Cuestiones relacionadas