¿Cómo funciona el locking exactamente?

Veo que para usar objetos que no son seguros para hilos, envolvemos el código con un locking como este:

private static readonly Object obj = new Object(); lock (obj) { // thread unsafe code } 

Entonces, ¿qué sucede cuando varios subprocesos acceden al mismo código (supongamos que se está ejecutando en una aplicación web ASP.NET). ¿Están en cola? Si es así, ¿cuánto tiempo esperarán?

¿Cuál es el impacto en el rendimiento debido al uso de lockings?

La instrucción de lock se traduce por C # 3.0 a lo siguiente:

 var temp = obj; Monitor.Enter(temp); try { // body } finally { Monitor.Exit(temp); } 

En C # 4.0 esto ha cambiado y ahora se genera de la siguiente manera:

 bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); // body } finally { if (lockWasTaken) { Monitor.Exit(temp); } } 

Puede encontrar más información sobre lo que hace Monitor.Enter aquí . Para citar a MSDN:

Use Enter para adquirir el Monitor en el objeto pasado como el parámetro. Si otro hilo ha ejecutado un Enter en el objeto pero aún no ha ejecutado la Exit correspondiente, el hilo actual se bloqueará hasta que el otro hilo libere el objeto. Es legal que el mismo hilo invoque Enter más de una vez sin bloquearlo; sin embargo, se debe invocar un número igual de llamadas de Exit antes de que se desbloqueen otros subprocesos que esperan en el objeto.

El método Monitor.Enter esperará infinitamente; no se apagará.

Es más simple de lo que piensas

Según Microsoft : la palabra clave de lock garantiza que un hilo no ingrese una sección crítica del código mientras que otro hilo está en la sección crítica. Si otro hilo intenta ingresar un código bloqueado, esperará, bloqueará, hasta que se libere el objeto.

La palabra clave de lock llama al principio del bloque y Exit al final del bloque. lock palabra clave lock realmente maneja la clase Monitor en el back-end.

Por ejemplo:

 private static readonly Object obj = new Object(); lock (obj) { // critical section } 

En el código anterior, el primer subproceso ingresa a la sección crítica y luego bloquea obj y cuando otro subproceso intenta ingresar, entonces también intentará bloquear obj que ya está bloqueado por el primer subproceso, tendré que esperar a que el primer subproceso libere el obj . y cuando primero se irá, el otro hilo bloqueará obj e ingresará a la sección crítica.

No, no están en cola, están durmiendo

Una statement de locking de la forma

 lock (x) ... 

donde x es una expresión de un tipo de referencia, es precisamente equivalente a

 var temp = x; System.Threading.Monitor.Enter(temp); try { ... } finally { System.Threading.Monitor.Exit(temp); } 

Solo necesita saber que están esperando el uno al otro, y solo un hilo entrará para bloquearlo, los otros esperarán …

El monitor está escrito completamente en .net por lo que es lo suficientemente rápido, también mira la clase Monitor con reflector para más detalles

Bloqueos impedirá que otros subprocesos ejecuten el código contenido en el bloque de locking. Los hilos tendrán que esperar hasta que se complete el hilo dentro del bloque de locking y se libere el locking. Esto tiene un impacto negativo en el rendimiento en un entorno multiproceso. Si necesita hacer esto, debe asegurarse de que el código dentro del bloque de locking pueda procesarse muy rápidamente. Debería tratar de evitar actividades costosas como acceder a una base de datos, etc.

El impacto en el rendimiento depende de la forma en que bloquee. Puede encontrar una buena lista de optimizaciones aquí: http://www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-contention-in-threaded-programs/

Básicamente debe intentar bloquear lo menos posible, ya que pone su código de espera en reposo. Si tiene algunos cálculos pesados ​​o un código de larga duración (por ejemplo, carga de archivos) en un locking, se produce una gran pérdida de rendimiento.

La parte dentro del enunciado de locking solo puede ejecutarse con un hilo, por lo que todos los otros hilos esperarán indefinidamente para que termine el hilo que contiene el locking. Esto puede resultar en un llamado punto muerto.

La instrucción de lock se traduce a llamadas a los métodos de Enter y Exit de Monitor .

La instrucción de lock esperará indefinidamente para que se libere el objeto de locking.

locking está realmente oculto clase de Monitor .