net - remarks c#
¿Cómo funciona el bloqueo exactamente? (8)
Veo que para usar objetos que no son seguros para hilos, envolvemos el código con un bloqueo 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 van a esperar?
¿Cuál es el impacto en el rendimiento debido al uso de bloqueos?
El impacto en el rendimiento depende de la forma en que se bloquea. 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 el código de espera en suspensión. Si tiene algunos cálculos pesados o un código de larga duración (por ejemplo, carga de archivos) en un bloqueo, se produce una gran pérdida de rendimiento.
Es más sencillo de lo que piensas.
Según Microsoft : la palabra clave de lock
garantiza que un subproceso no ingrese a una sección crítica del código mientras que otro subproceso 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 Enter
al inicio del bloque y Exit
al final del bloque. lock
palabra clave de 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 entra en la sección crítica, entonces bloqueará el obj
y cuando otro subproceso intente ingresar, también intentará bloquear el obj
que ya está bloqueado por el primer subproceso, tendré que esperar que el primer subproceso libere el obj
. y cuando saldrá primero, otro hilo bloqueará el objeto y entrará en la sección crítica.
La declaración de lock
es traducida 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 Monitor.Enter
hace here . Para citar MSDN:
Utilice
Enter
para adquirir el Monitor en el objeto pasado como parámetro. Si otro subproceso ha ejecutado unEnter
en el objeto pero aún no ha ejecutado laExit
correspondiente, el subproceso actual se bloqueará hasta que el otro subproceso libere el objeto. Es legal que el mismo hilo invoqueEnter
más de una vez sin que se bloquee; sin embargo, debe invocarse un número igual de llamadas deExit
antes de que se desbloqueen otros subprocesos que esperan en el objeto.
El método Monitor.Enter
esperará infinitamente; no va a expirar.
La declaración de lock
se traduce en llamadas a los métodos de Enter
y Exit
del Monitor
.
La instrucción de lock
esperará indefinidamente a que se libere el objeto de bloqueo.
La parte dentro de la sentencia de bloqueo solo puede ser ejecutada por un subproceso, por lo que todos los otros subprocesos esperarán indefinidamente a que finalice el subproceso que mantiene el bloqueo. Esto puede resultar en un llamado interbloqueo.
Los bloqueos impedirán que otros subprocesos ejecuten el código contenido en el bloque de bloqueo. Los hilos tendrán que esperar hasta que el hilo dentro del bloque de bloqueo se haya completado y el bloqueo se libere. 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 bloqueo de bloqueo pueda procesarse muy rápidamente. Debe intentar evitar actividades costosas como acceder a una base de datos, etc.
No, no están en cola, están durmiendo.
Una declaración de bloqueo de la forma
lock (x) ...
donde x es una expresión de un tipo de referencia, es exactamente equivalente a
var temp = x;
System.Threading.Monitor.Enter(temp);
try { ... }
finally { System.Threading.Monitor.Exit(temp); }
Solo debes saber que están esperando el uno al otro, y solo un hilo ingresará para bloquear el bloqueo, los otros esperarán ...
El monitor está escrito completamente en .net, por lo que es lo suficientemente rápido, también consulte la clase Monitor con reflector para obtener más detalles