2012-03-08 13 views
20

Esto es de MSDN: La palabra clave de bloqueo asegura que un hilo no entra una sección crítica de código mientras otro hilo está en la sección crítica.La confusión acerca de la declaración de bloqueo en C#

¿Tiene una sección crítica tiene por qué ser el mismo que la sección crítica?

O significa: La palabra clave de bloqueo asegura que un hilo no entra cualquier sección crítica vigilado por un objeto de código mientras otro hilo está en cualquier sección crítica vigilado por el mismo objeto. ?

class Program 
{ 
    static void Main(string[] args) 
    { 
     TestDifferentCriticalSections(); 

     Console.ReadLine(); 
    } 

    private static void TestDifferentCriticalSections() 
    { 
     Test lo = new Test(); 

     Thread t1 = new Thread(() => 
     { 
      lo.MethodA(); 
     }); 
     t1.Start(); 

     Thread t2 = new Thread(() => 
     { 
      lo.MethodB(); 
     }); 
     t2.Start(); 
    } 
} 

public class Test 
{ 
    private object obj = new object(); 

    public Test() 
    { } 

    public void MethodA() 
    { 
     lock (obj) 
     { 
      for (int i = 0; i < 5; i++) 
      { 
       Thread.Sleep(500); 
       Console.WriteLine("A"); 
      } 
     } 
    } 

    public void MethodB() 
    { 
     lock (obj) 
     { 
      for (int i = 0; i < 5; i++) 
      { 
       Thread.Sleep(500); 
       Console.WriteLine("B"); 
      } 
     } 
    } 
} 
+3

Se trata más de Gramática que C#, "la" es definitiva, mientras que "a" es indefinida y podría estar refiriéndose a cualquier sección de código. http://www.englishclub.com/grammar/adjectives-determiners-the-a-an.htm – Lloyd

Respuesta

63

La pregunta está redactada de forma confusa y las respuestas hasta ahora tampoco son particularmente claras. Permítanme reformular la pregunta en varias preguntas:

(1) ¿La instrucción de bloqueo garantiza que no haya más de un hilo en el cuerpo de la instrucción de bloqueo al mismo tiempo?

No. Por ejemplo:

static readonly object lock1 = new object(); 
static readonly object lock2 = new object(); 
static int counter = 0; 
static object M() 
{ 
    int c = Interlocked.Increment(ref counter); 
    return c % 2 == 0 ? lock1 : lock2; 
} 

... 
lock(M()) { Critical(); } 

Es posible que los dos hilos a ambos estar en el cuerpo de la declaración de bloqueo al mismo tiempo, porque los bloqueos de los estados de bloqueo en dos objetos diferentes. Thread Alpha puede llamar a M() y obtener lock1, y luego el thread Beta puede llamar a M() y obtener lock2.

(2) Suponiendo que mi instrucción de bloqueo siempre se bloquea en el mismo objeto, ¿una instrucción de bloqueo asegura que no haya más de un subproceso "activo" en el cuerpo del bloqueo en un momento dado?

Sí. Si usted tiene:

static readonly object lock1 = new object(); 
... 
lock(lock1) { Critical(); } 

luego pase Alfa puede tomar la cerradura, y el hilo beta bloque hasta que el bloqueo está disponible antes de entrar en el cuerpo de la cerradura.

(3) Suponiendo que tengo dos declaraciones de bloqueo, y las dos declaraciones cerradura de bloqueo en el mismo objeto cada vez, se asegura un comunicado de bloqueo que hay más de un hilo "activo" está en el cuerpo de cualquiera de bloqueo ¿en cualquier momento?

Sí.Si usted tiene:

static readonly object lock1 = new object(); 
... 
static void X() 
{ 
    lock(lock1) { CriticalX(); } 
} 
static void Y() 
{ 
    lock(lock1) { CriticalY(); } 
} 

entonces, si el hilo Alpha es en X y usa el cierre, y el hilo Beta es en Y, luego pase beta bloque hasta que el bloqueo está disponible antes de entrar en el cuerpo de la cerradura.

(4) ¿Por qué estás poniendo "activo" en "citas de miedo"?

Para llamar la atención sobre el hecho de que es posible que un esperando hilo para estar en el cuerpo de la cerradura. Puede usar el método Monitor.Wait para "pausar" un hilo que está en un cuerpo de cerradura y permitir que un hilo bloqueado se active e ingrese ese cuerpo de cerradura (o un cuerpo de cerradura diferente que traba el mismo objeto). El hilo de espera permanecerá en estado de "espera" hasta que se pulse. En algún momento después de pulsar, vuelve a unirse a la cola "lista" y a los bloques hasta que no haya ningún hilo "activo" en la cerradura. Luego se reanuda en el punto donde lo dejó.

+3

Como siempre, sus respuestas superan con mucho a las mías en profundidad y exactitud. Y para eso, te colmaré de votaciones. –

+1

Y nuevamente, me alegro de leer una de sus respuestas. Gracias Eric. – MoonKnight

+1

+1 por poner * activo * en las citas de miedo. ;-) Es muy necesario aquí. – Nawaz

5

Pone un candado en un objeto. Si otro hilo intenta acceder a una sección crítica marcada por ese objeto al mismo tiempo, se bloqueará hasta que se elimine/complete el bloqueo.

Ejemplo:

public static object DatabaseLck= new object(); 

lock (DatabaseLck) { 
     results = db.Query<T>(query).ToList(); 
    } 

O

lock (DatabaseLck) { 
     results = db.Query<T>(string.Format(query, args)).ToList(); 
    } 

Ni uno de esos bloques de código se puede ejecutar al mismo tiempo, debido a que utilizan el mismo objeto de bloqueo. Si utilizó un objeto de bloqueo diferente para cada uno, podrían ejecutarse al mismo tiempo.

+0

"Si otro hilo intenta acceder a ese objeto al mismo tiempo, bloqueará" - ¿Quiso decir: "Si otro hilo intenta acceder a una sección crítica marcada por ese objeto al mismo tiempo, bloqueará "? – CuiPengFei

+0

Sí. Gracias. He actualizado mi respuesta. –

0

No, significa que otro subproceso no entrará en la sección crítica protegida por esta instrucción de bloqueo.

la sección crítica se define solamente por el programador, y en este caso, se podría sustituirlo por: la sección protegida por una cerradura

Así traducción: La palabra clave lock asegura que un hilo no entra en una sección de código protegido por un lock mientras que otro hilo está en esta sección de código (protegido por un lock)

+2

¿No debería significar que se trata de una sección protegida por el mismo objeto de bloqueo? – erict

+0

No, porque el objeto que usa en el candado solo se usa para garantizar el candado. – squelos

+1

@squelos: cualquier sección que se bloquea en el mismo objeto está bloqueada por un bloqueo en ese objeto. –

2

Es una y la misma sección crítica.

lock (synclock) 
{ 
    // the critical section protected by the lock statement 
    // Only one thread can access this at any one time 
} 

Ver lock Statement en MSDN:

La expresión lock marca un bloque de instrucciones como una sección crítica mediante la obtención de la cerradura de exclusión mutua para un objeto dado, la ejecución de una declaración, y luego liberar el bloqueo .


o significa: La palabra clave de bloqueo asegura que un hilo no entra en ninguna sección crítica de código mientras otro hilo es de ninguna sección crítica. ?

No. No significa eso. Significa la sección crítica protegida por ese bloqueo y ese bloqueo solo.


actualización, ejemplo de código siguiente:

Si utiliza un solo objeto para bloquear el, se bloqueará todos secciones críticas, causando otros hilos para bloquear hasta que sea liberado. En su ejemplo de código, una vez que se ingresó el bloqueo en MethodA, todos los demás hilos que lleguen a ese bloqueo y el bloqueo en MethodB se bloquearán hasta que se libere el bloqueo (esto sucede porque está bloqueando el mismo objeto en ambos métodos).

+0

downvote: consulte el código que agregué a la publicación – CuiPengFei

+0

@CuiPengFei - Answer updated. – Oded

0

La sección crítica de la que está hablando es la sección protegida por las instrucciones de bloqueo.

Cualquier sección crítica que se bloquee en el mismo objeto no podrá acceder.

También es importante que el objeto de bloqueo sea estático, ya que los bloqueos deben bloquearse (o intentarse bloquear) en la misma instancia del objeto de bloqueo.

+5

** No use el doble bloqueo a menos que tenga un problema de rendimiento demostrado con el bloqueo adecuado. ** Hay aproximadamente un millón de maneras de verificar el bloqueo incorrecto y solo una forma de hacerlo bien; es un patrón * insanamente peligroso * cuando se usa descuidadamente. Si crees que deberías utilizar el bloqueo con doble verificación, * piénsalo de nuevo *. Probablemente pueda resolver su problema con (1) bloqueo regular, (2) intercambio interconectado, (3) la clase Lazy , (4) aprovechando la semántica de bloqueo del inicializador de clase estática. –

+0

@EricLippert: Siempre tuve la impresión de que el bloqueo con doble verificación era una necesidad. Gracias por la aclaración. He eliminado ese comentario de mi respuesta, pero creo que el resto sigue siendo un escrutinio. –

+0

No, el bloqueo con doble verificación es una * técnica de bloqueo bajo para la optimización del rendimiento *, y como cualquier técnica de bloqueo bajo, es una locura peligrosa. –

1

No significa cualquier, aunque puede proteger 2 bloques de código para que no sean ingresados ​​por más de un hilo al mismo tiempo al encerrarlos con el mismo objeto. Este es un paradigma común: es posible que desee bloquear su colección para borrar y escribir.

Cuestiones relacionadas