false example configureawait await async c# asp.net deadlock

example - configureawait false c#



¿Por qué los bloqueos anidados no causan un punto muerto? (3)

¿Por qué este código no causa un punto muerto?

private static readonly object a = new object();

...

lock(a) { lock(a) { .... } }


De la sección 8.12 de la especificación del lenguaje C #:

Mientras se mantiene un bloqueo de exclusión mutua, el código que se ejecuta en el mismo subproceso de ejecución también puede obtener y liberar el bloqueo. Sin embargo, el código que se ejecuta en otros hilos está bloqueado para obtener el bloqueo hasta que se libere el bloqueo.

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


La palabra clave de lock usa un bloqueo de reentrantes, lo que significa que el hilo actual ya tiene el bloqueo, por lo que no intenta volver a adquirirlo.

Un punto muerto ocurre si

El subproceso 1 adquiere el bloqueo A
El hilo 2 adquiere el bloqueo B
El subproceso 1 intenta adquirir el bloqueo B (espera a que se complete el subproceso 2) El subproceso 2 intenta obtener el bloqueo A (espera a que se complete el subproceso 1)

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


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

En cuanto a por qué es así, (y por qué es una buena idea), considere la siguiente situación, donde tenemos un orden de bloqueo definido en otro lugar 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 nuestra orden de bloqueo y tenemos un punto muerto potencial en nuestras manos.

Realmente necesitamos poder 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 } }

Para que nuestro orden de bloqueo se mantenga, sin autobloqueo cuando llamemos a f() .