2009-08-11 13 views
9

Tengo el siguiente código:¿Qué tan profundo funciona un candado?

  locker = new object(); 
     lock (locker) 
     { 
      for (int i = 0; i < 3; i++) 
       ver_store[i] = atomic_Poll(power);     
     } 

Estaba vagando, teniendo en cuenta la función dentro de la cerradura accede a algunos recursos globales, (un socket abierto entre ellos) si todos los recursos globales dentro del objeto también se bloquean. (Soy consciente de que cualquier otra función que tenga acceso a estas mismas variables debe implementar un bloqueo en ellos también para que el mecanismo de bloqueo sea válido. No he podido bloquearlos aún :))

Respuesta

11

comunicado El bloqueo no "Código de bloqueo" o cualquier recurso que va en entre las llaves pre se.

Encuentro que es mejor entender el bloqueo desde la perspectiva de un hilo (después de todo, en los escenarios de subprocesamiento es cuando debe considerar el bloqueo).

Dada su código de ejemplo

10 locker = new object(); 
11 lock (locker) 
12 { 
    ... 
15 } 

Cuando hilo X alcanza la línea 10 se crea un nuevo objeto y en la línea 11 una cerradura se adquiere en el objeto. El hilo X continúa ejecutando cualquier código que esté dentro del bloque.

Ahora, mientras que el hilo X está en el medio de nuestro bloque, el hilo Y llega a la línea 10. Y he aquí que se crea un objeto nuevo y, como está creado por el hilo Y, no se adquiere ningún bloqueo en este objeto. Por lo tanto, cuando la rosca Y llegue a 11, conseguirá con éxito un bloqueo en el objeto y continuará ejecutando el bloque al mismo tiempo que la rosca X.

Esta es la situación que se suponía que el bloqueo debía evitar. ¿Entonces lo que hay que hacer? Haga que el casillero sea un objeto compartido .

01 static object locker = new object(); 

    ... 

11 lock (locker) 
12 { 
    ... 
15 } 

Ahora, cuando el hilo X llega a la línea 11, adquirirá el bloqueo y comenzará la ejecución del bloque. Cuando el hilo Y alcanza la línea 11 intentará adquirir un bloqueo en el mismo objeto que el hilo X. Como este objeto ya está bloqueado, el hilo Y esperará hasta que se libere el bloqueo. De este modo, se evita la ejecución concurrente del bloque de código, protegiendo así los recursos utilizados por ese código para que se acceda simultáneamente.

Nota: si otras partes de su sistema se deben serializar con los mismos recursos, todas deben intentar bloquear el mismo objeto de bloque compartido.

+0

Una explicación aún mejor para un principiante. Muchas gracias oh muchísimo –

+0

Eres totalmente bienvenido :) –

3

Es muy simple- el bloqueo bloquea el código dentro de la instrucción de bloqueo. Si usa esos recursos en otro lugar de su código, no estarán cubiertos por ese bloqueo.

Algunas clases tienen mecanismos en ellas para que pueda bloquear en varios lugares; un ejemplo de esto es el Hashtable's Syncroot property. La utilidad de esto es questionable though. A nice discussion about it is on SO.

Su mejor apuesta es encapsular esta lógica en su propia clase, con un mecanismo de bloqueo interno, y asegúrese de que su aplicación use solo esa clase.

1

El bloqueo no se relaciona con algún objeto; se relaciona solo con un fragmento de código. Entonces, si tienes 2 funciones diferentes que funcionan con un socket global, debes controlarlas, para tu ejemplo debe ser el mismo objeto 'Locker', así que hazlo visible para ambas partes del código.

4

El bloqueo solo afecta al código en el cuerpo de la instrucción de bloqueo. Los objetos pasados ​​como un parámetro actúan como un identificador único, no se afecta internamente de ninguna manera.

1

Respuesta corta: No

de bloqueo es un concepto lógico, no un físico único donde la lengua/cpu infiere el alcance de una cerradura y restringe el acceso a todas las partidas dentro del alcance. Es su trabajo imponer el uso del bloqueo, por lo que si tiene que adquirir el bloqueo X para usar el recurso Y, entonces debe asegurarse de hacerlo siempre.

3

Como se ha mencionado por todo el mundo por aquí ...

  • bloqueo es un concepto lógico
  • bloqueo sólo bloquea ¿qué hay en el bloque de código dentro de las llaves.

Pero para darle una breve visión:

bloqueo no es más que un reemplazo para Monitor.Enter y Monitor.Exit. Solo eso, con el bloqueo Monitor.Exit se coloca en un bloque finally.

Por lo tanto, lo que eres REALMENTE bloqueo es (en tu código) es el objeto de la taquilla. Entonces, en cualquier lugar de su código, si usa este objeto de bloqueador para bloquearlo, ese bloque de código quedará bloqueado.

Mi conjetura es que esta es la forma en la cerradura funciona: (gurús, por favor, corríjanme si me equivoco)

if(locker.SyncBlockIndex <0)>              
{                     
//obtain an index to free synch cache block          
//assign the index obtained in previous step to obj.SyncBlockIndex    
}                     
syncblock = syncblockCache[locker.SyncBlockIndex]         
if(!syncblock is owned by the calling thread)          
{                     
//susped the calling thread              
}    

Ver si este enlace le ayuda a comprender la cerradura (que había escrito este post hace algún tiempo)

http://dotenetscribbles.blogspot.com/2008/10/calling-monitorenter-recursively.html

2

un bloqueo es sólo una muestra. Siempre que un hilo esté manteniendo un bloqueo específico, otros hilos no podrán obtener dicho bloqueo y, por lo tanto, se les impedirá ejecutar el código que se sincroniza utilizando el bloqueo en cuestión.

Es posible que desee comprobar las respuestas a esta pregunta así: Does lock(){} lock a resource, or does it lock a piece of code?

Cuestiones relacionadas