2011-02-17 14 views
38

Duplicar posible:
Re-entrant locks in C#¿Por qué las cerraduras anidadas no causan un interbloqueo?

¿Por qué este código no causa un callejón sin salida?

private static readonly object a = new object(); 

...

lock(a) 
    { 
     lock(a) 
     { 
     .... 
     } 
    } 
+0

¿Por qué esperas que se produzca un punto muerto? (también, esto es bastante similar a http://stackoverflow.com/questions/391913/re-entrant-locks-in-c que puede ayudar) – AakashM

+3

Esto es claramente un duplicado de eso, pero el título de esta pregunta es infinitamente mejor (para las personas que probablemente lo buscarían). –

Respuesta

34

Si un hilo ya tiene un bloqueo, entonces puede "tomar ese bloqueo" nuevamente sin problema.


En cuanto a qué es decir, (y eso que es una buena idea), considere la siguiente situación, donde tenemos un bloqueo definido ordenar otra parte del programa de a -> b:

void f() 
{ 
    lock(a) 
    { /* do stuff inside a */ } 
} 

void doStuff() 
{ 
    lock(b) 
    { 
     //do stuff inside b, that involves leaving b in an inconsistent state 
     f(); 
     //do more stuff inside b so that its consistent again 
    } 
} 

Vaya, acabamos de violar nuestro orden de bloqueo y tenemos un posible punto muerto en nuestras manos.

Nos realmente necesitamos ser capaces de hacer lo siguiente:

function doStuff() 
{ 
    lock(a) 
    lock(b) 
    { 
     //do stuff inside b, that involves leaving b in an inconsistent state 
     f(); 
     //do more stuff inside b so that its consistent again 
    } 
} 

Así que nuestro pedido de bloqueo se mantiene, sin auto-interbloqueos cuando nos llaman f().

+1

+1 por qué y un buen ejemplo de cuándo utilizarías la función. – Myster

+0

¿Puedes explicar por qué hay un punto muerto? Tu orden de bloqueo me parece consistente. Todas las rutas de acceso de código A O B-> A no hay una ruta de código para bloquear A-> B –

+1

@JaredKells Se define justo antes del primer bloque de código; .... donde tenemos un orden de bloqueo definido ** en otro lugar del programa ** de a -> b: – Mr47

18

El lock palabra clave utiliza un entrante de bloqueo, es decir, el hilo actual ya tiene la cerradura para que no intente volver a adquirir la misma.

se produce un interbloqueo si

Thread 1 adquiere bloquear un
rosca 2 adquiere bloqueo B
Thread 1 intenta adquirir bloqueo B (espera para el hilo 2 para ser realizadas con ella) rosca 2 intenta adquirir bloqueo A (espera a que se complete el Hilo 1)

Ambos hilos están esperando el uno al otro y, por lo tanto, estancados.

+0

Intentando encontrar un ejemplo de bloqueo no reentrante, pero Google me está fallando. – Davy8

+1

[ReaderWriterLockSlim] (http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim%28v=vs.110%29.aspx) es un ejemplo. – Chuu

8

De section 8.12 de la especificación de lenguaje C#:

Mientras se lleva a cabo un bloqueo de exclusión mutua, código que se ejecuta en el mismo hilo de ejecución también puede obtener y liberar el bloqueo . Sin embargo, el código que se ejecuta en otros subprocesos está bloqueado para que no se obtenga el bloqueo hasta que se libere el bloqueo.

Debería ser obvio que el alcance interno lock está en el mismo hilo que el exterior.

Cuestiones relacionadas