2010-03-09 19 views
10

Tengo una función que devuelve una entrada en un diccionario, basada en la clave (nombre) y, si no existe, devuelve una nueva.Diccionario de bloqueo dentro del mismo hilo

La pregunta que tengo es con el "bloqueo doble": SomeFunction bloquea el _diccionario, para verificar la existencia de la clave, luego llama a una función que también bloquea el mismo diccionario, parece funcionar, pero no estoy seguro si hay un problema potencial con este enfoque.

public Machine SomeFunction(string name) 
{ 
    lock (_dictionary) 
    { 
     if (!_dictionary.ContainsKey(name)) 
        return CreateMachine(name); 
     return _dictionary[name]; 
    } 
} 


private Machine CreateMachine(string name) 
{ 
    MachineSetup ms = new Machine(name); 
    lock(_dictionary) 
    { 
     _ictionary.Add(name, ms); 
    } 
    return vm; 
} 
+8

Creo que no entiende lo que hace el bloqueo. Locking ** bloquea todos los demás hilos para que no tengan acceso a la región protegida de código **. No hace nada en absoluto con el hilo * actual *. Puede sacar un bloqueo mil veces en el mismo objeto en el mismo subproceso, no hay problema; cada región de código bloqueada de este modo estará protegida contra el acceso por otros hilos. –

+0

Si está buscando "bloqueos del mismo hilo", consulte la clase [Semaphore] (http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx). – ANeves

Respuesta

10

Garantizado que funciona: los bloqueos son recursivos en .NET. Si es realmente una buena idea o no es una cuestión diferente ... ¿qué hay de esto en su lugar:

public Machine SomeFunction(string name) 
{ 
    lock (_dictionary) 
    { 
     Machine result; 
     if (!_dictionary.TryGetValue(name, out result)) 
     { 
      result = CreateMachine(name); 
      _dictionary[name] = result; 
     } 
     return result; 
    } 
} 

// This is now *just* responsible for creating the machine, 
// not for maintaining the dictionary. The dictionary manipulation 
// is confined to the above method. 
private Machine CreateMachine(string name) 
{ 
    return new Machine(name); 
} 
+0

@Jon Skeet: ¿Solo para verificarlo por mí mismo, uno no debería tratar de obtener el valor en lugar de bloquear el diccionario de inmediato? ¿Te gusta bloquear solo cuando el método TryGetValue() devuelve falso? –

+2

@Will Marcouiller: su esquema permitiría que un hilo modifique el diccionario mientras otro hilo lo está leyendo. Si la clase de diccionario se diseñó específicamente para permitir eso, entonces es posible que se realice algún esquema a lo largo de esas líneas (con un TryGetValue adicional después de tomar el bloqueo). Sin embargo, las colecciones generalmente no están diseñadas para usarse de esta manera, y la clase de diccionario incorporada se encuentra entre las que nunca se deben leer y escribir al mismo tiempo. –

+0

¡Gracias por esta gran explicación, Jeffrey! Juraría precisamente que algunos de mis colegas ya han usado TryGetValue() antes y después del bloqueo() de la Colección. Esto podría haber sido un mal uso de ellos entonces. ¡Gracias! Recordaré eso. =) –

3

No hay problema aquí, el bloqueo se re-entrante por el mismo hilo. No todos los objetos de sincronización tienen afinidad de subprocesos, como Semaphore. Pero Mutex y Monitor (bloqueo) están bien.

Cuestiones relacionadas