¿Cuándo usaría AutoResetEvent y ManualResetEvent en lugar de Monitor.Wait () / Monitor.Pulse ()?
-
03-07-2019 - |
Pregunta
Ambos parecen cumplir el mismo propósito. ¿Cuándo elegiría uno sobre el otro?
Solución
Use los eventos cuando tenga un hilo que esté esperando en uno o en varios eventos para hacer algo.
Use el monitor si desea restringir el acceso a una estructura de datos limitando la cantidad de hilos que pueden acceder a ella.
Los monitores generalmente protegen un recurso, mientras que los eventos le informan que algo está sucediendo, como el cierre de la aplicación.
Además, los eventos se pueden nombrar (ver el método OpenExisting), esto les permite ser utilizados para la sincronización entre diferentes procesos.
Otros consejos
En mi opinión, es mejor usar Monitor si puedes, Monitor.Wait y Monitor.Pulse / PulseAll se usan para señalizar entre hilos (como lo son Manual / AutoResetEvent), sin embargo, Monitor es más rápido y no usa un nativo recurso del sistema También, aparentemente, Monitor se implementa en modo de usuario y se gestiona, mientras que Manual / AutoResetEvents requieren cambiar al modo kernel y p / invocar a las llamadas nativas de win32 que usan un controlador de espera.
Hay situaciones en las que necesitaría usar Manual / AutoResetEvent, por ejemplo, para señalar entre procesos que puede usar eventos con nombre, y supongo que para señalar hilos nativos en su aplicación.
Solo estoy regurgitando lo que he leído en este excelente artículo sobre el enhebrado.
Vale la pena leer todo el artículo, sin embargo, el enlace lo lleva a la sección de control de espera que detalla los eventos y controla la espera / pulso.
Usaría un WaitHandle
cuando desea que un hilo envíe o reciba una señal binaria sin la necesidad de una sección crítica. Monitor.Wait
y Monitor.Pulse
por otro lado requieren una sección crítica. Como la mayoría de los mecanismos de sincronización en el BCL, hay cierta superposición en cómo se pueden usar los dos que mencionó. Pero, no piense por un momento que cumplen el mismo propósito.
Monitor.Wait
y Monitor.Pulse
son un mecanismo de sincronización mucho más primitivo que un MRE o ARE. De hecho, puedes construir un MRE o ARE utilizando nada más que la clase Monitor
. El concepto más importante para entender es cómo difieren los métodos Monitor.Wait
y WaitHandle.WaitOne
. Wait
y WaitOne
colocarán el hilo en el estado WaitSleepJoin
, lo que significa que el hilo queda inactivo y solo responde a un hilo . Interrumpir
o la llamada respectiva Pulse
o Set
. Pero, y esta es una diferencia importante, Wait
dejará una sección crítica y la volverá a adquirir de manera atómica . WaitOne
simplemente no puede hacer esto. Es una diferencia tan fundamental en la forma en que se comportan estos mecanismos de sincronización que define los escenarios en los que se pueden utilizar.
En la mayoría de las situaciones, elegiría un MRE o ARE. Estos satisfacen la mayoría de las situaciones en las que un hilo necesita recibir una señal de otro. Sin embargo, si desea crear su propio mecanismo de señalización, deberá usar Wait
y Pulse
. Pero, de nuevo, el .NET BCL ya tiene cubiertos la mayoría de los mecanismos de señalización populares. Los siguientes mecanismos de señalización ya existen 1 .
- ManualResetEvent (o ManualResetEventSlim)
- AutoResetEvent
- Semáforo (o SemaphoreSlim)
- EventWaitHandle
- CountdownEvent
- Barrera
1 Una mención de honor va a la clase BlockingCollection
. No es un mecanismo de señalización per se, pero tiene las cualidades de un mecanismo de señalización con el beneficio adicional de que puede adjuntar datos a la señal. En este caso, la señal significa que un elemento está disponible en la colección y los datos asociados con esa señal son el elemento mismo.
Este tutorial tiene descripciones detalladas de lo que necesitará saber: http://www.albahari.com/threading/
En particular, esto cubrirá las clases XXXResetEvent,
http://www.albahari.com/threading/part2.aspx
y esto cubrirá Wait / Pulse: http://www.albahari.com/threading/part4.aspx#_Wait_and_Pulse