¿Alguien puede explicar la diferencia entre:
- bloqueo (algún objeto) {}
- Usando Mutex
- Usando el semáforo
- Usando Monitor
- Uso de otras clases de sincronización .Net
Simplemente no puedo entenderlo. ¿Me parece que los dos primeros son iguales?
¿Alguien puede explicar la diferencia entre:
Simplemente no puedo entenderlo. ¿Me parece que los dos primeros son iguales?
Respuestas:
Gran pregunta Tal vez me equivoque ... Déjame intentarlo ... Revisión # 2 de mi respuesta original ... con un poco más de comprensión. Gracias por hacerme leer :)
cerradura (obj)
Monitores
El uso de un bloqueo o monitor es útil para evitar la ejecución simultánea de bloques de código sensibles a hilos, pero estas construcciones no permiten que un hilo comunique un evento a otro. Esto requiere eventos de sincronización , que son objetos que tienen uno de dos estados, señalizados y no señalizados, que se pueden usar para activar y suspender subprocesos. Mutex, semáforos son conceptos a nivel del sistema operativo. por ejemplo, con un mutex con nombre que podría sincronizar a través de múltiples exes (administrados) (asegurando que solo una instancia de su aplicación se esté ejecutando en la máquina).
Mutex:
Semáforos (me duelen el cerebro).
Monitor
no permite la comunicación es incorrecta; todavía puedes, Pulse
etc. con unMonitor
Re "Uso de otras clases de sincronización .Net" - algunas de las otras que debe conocer:
También hay más construcciones de bloqueo (gastos generales bajos) en CCR / TPL (el CTP de extensiones paralelas ), pero IIRC, estarán disponibles en .NET 4.0
Como se indica en ECMA, y como puede observar en los métodos Reflejados, la declaración de bloqueo es básicamente equivalente a
object obj = x;
System.Threading.Monitor.Enter(obj);
try {
…
}
finally {
System.Threading.Monitor.Exit(obj);
}
Del ejemplo antes mencionado vemos que los Monitores pueden bloquear objetos.
Los Mutexe son útiles cuando necesita sincronización entre procesos, ya que pueden bloquear un identificador de cadena. El mismo identificador de cadena puede ser utilizado por diferentes procesos para adquirir el bloqueo.
Los semáforos son como mutexes en los esteroides, permiten el acceso concurrente al proporcionar un conteo máximo de acceso concurrente '. Una vez que se alcanza el límite, el semáforo comienza a bloquear cualquier acceso adicional al recurso hasta que una de las personas que llama suelte el semáforo.
Hice las clases y el soporte de CLR para subprocesos en DotGNU y tengo algunos pensamientos ...
A menos que requiera bloqueos de proceso cruzado, siempre debe evitar usar Mutex y semáforos. Estas clases en .NET son envoltorios alrededor de Win32 Mutex y Semáforos y son bastante pesadas (requieren un cambio de contexto en el Kernel que es costoso, especialmente si su bloqueo no está bajo contención).
Como se menciona a otros, la declaración de bloqueo de C # es magia del compilador para Monitor.Enter y Monitor.Exit (existente dentro de un intento / finalmente).
Los monitores tienen un mecanismo de señal / espera simple pero potente que Mutexes no tiene a través de los métodos Monitor.Pulse / Monitor.Wait. El equivalente de Win32 serían objetos de evento a través de CreateEvent que en realidad también existen en .NET como WaitHandles. El modelo Pulse / Wait es similar a pthread_signal y pthread_wait de Unix, pero son más rápidos porque pueden ser operaciones completamente en modo de usuario en el caso no disputado.
Monitor.Pulse / Wait es fácil de usar. En un subproceso, bloqueamos un objeto, verificamos un indicador / estado / propiedad y, si no es lo que esperamos, llama a Monitor.Wait, que liberará el bloqueo y esperará hasta que se envíe un pulso. Cuando la espera regresa, retrocedemos y verificamos la bandera / estado / propiedad nuevamente. En el otro hilo, bloqueamos el objeto cada vez que cambiamos la bandera / estado / propiedad y luego llamamos a PulseAll para despertar cualquier hilo de escucha.
A menudo queremos que nuestras clases sean seguras para subprocesos, por lo que ponemos bloqueos en nuestro código. Sin embargo, a menudo ocurre que nuestra clase solo será utilizada por un hilo. Esto significa que los bloqueos ralentizan innecesariamente nuestro código ... aquí es donde las optimizaciones inteligentes en el CLR pueden ayudar a mejorar el rendimiento.
No estoy seguro acerca de la implementación de bloqueos de Microsoft, pero en DotGNU y Mono, un indicador de estado de bloqueo se almacena en el encabezado de cada objeto. Cada objeto en .NET (y Java) puede convertirse en un bloqueo, por lo que cada objeto debe admitir esto en su encabezado. En la implementación de DotGNU, hay un indicador que le permite usar una tabla hash global para cada objeto que se usa como bloqueo; esto tiene el beneficio de eliminar una sobrecarga de 4 bytes para cada objeto. Esto no es excelente para la memoria (especialmente para los sistemas integrados que no están muy enhebrados) pero tiene un impacto en el rendimiento.
Tanto Mono como DotGNU utilizan eficazmente mutexes para realizar bloqueos / espera, pero utilizan un estilo de comparación de cambio de spinlock para eliminar la necesidad de realizar bloqueos duros a menos que sea realmente necesario:
Puede ver un ejemplo de cómo se pueden implementar los monitores aquí:
http://cvs.savannah.gnu.org/viewvc/dotgnu-pnet/pnet/engine/lib_monitor.c?revision=1.7&view=markup
Una advertencia adicional para bloquear cualquier Mutex compartido que haya identificado con una ID de cadena es que, por defecto, será un mutex "Local \" y no se compartirá entre sesiones en un entorno de servidor de terminal.
Prefije su identificador de cadena con "Global \" para garantizar que el acceso a los recursos compartidos del sistema se controle adecuadamente. Me encontraba con un montón de problemas al sincronizar las comunicaciones con un servicio que se ejecutaba bajo la cuenta SYSTEM antes de darme cuenta de esto.
Intentaría evitar "lock ()", "Mutex" y "Monitor" si puedes ...
Echa un vistazo al nuevo espacio de nombres System.Collections.Concurrent en .NET 4
Tiene algunas buenas clases de colección seguras para subprocesos
http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx
ConcurrentDictionary rocks! ¡ya no hay bloqueo manual para mí!
En la mayoría de los casos no deberías usar bloqueos (= Monitores) o mutexes / semáforos. Todos bloquean el hilo actual.
Y definitivamente no deberías usar System.Collections.Concurrent
clases: son la principal fuente de condiciones de carrera porque no admiten transacciones entre varias colecciones y también bloquean el hilo actual.
Sorprendentemente .NET no tiene mecanismos efectivos para la sincronización.
Implementé la cola en serie de GCD ( Objc/Swift
mundo) en C #, una herramienta de sincronización muy liviana, que no bloquea y que usa un grupo de subprocesos, con pruebas.
Es la mejor manera de sincronizar cualquier cosa en la mayoría de los casos, desde el acceso a la base de datos (hola sqlite) hasta la lógica empresarial.