2010-03-09 8 views
10

Ho una funzione che restituisce una voce su un dizionario, basata sulla chiave (nome) e, se non esiste, ne restituisce una appena creata.Blocca il dizionario all'interno della stessa discussione

La domanda che ho è con il "doppio blocco": SomeFunction blocca il _dictionary, per verificare l'esistenza della chiave, quindi chiama una funzione che blocca anche lo stesso dizionario, sembra funzionare ma non sono sicuro se c'è un potenziale problema con questo approccio.

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

Penso che tu stia fraintendendo il blocco. Il blocco ** blocca tutti gli altri thread dall'accesso alla regione protetta del codice **. Non fa assolutamente nulla al thread * current *. Puoi eliminare un lucchetto un migliaio di volte sullo stesso oggetto sullo stesso thread, nessun problema; ogni regione di codice bloccata in tal modo sarà protetta dall'accesso da altri thread. –

+0

Se stai cercando "lock con lo stesso thread", guarda nella classe [Semaphore] (http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx). – ANeves

risposta

10

Questo è garantito per funzionare - i blocchi sono ricorsivi in. NET. Che si tratti di una buona idea o no è una questione diversa ... che ne dite di questo, invece:

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 per verificare da solo, non si dovrebbe cercare di ottenere il valore invece di bloccare il dizionario subito? Come si blocca solo quando il metodo TryGetValue() restituisce false? –

+2

@Will Marcouiller: lo schema consente a un thread di modificare il dizionario mentre un altro thread lo sta leggendo. Se la classe del dizionario è stata specificamente progettata per consentire ciò, allora alcuni schemi lungo quelle linee potrebbero essere possibili (con un TryGetValue aggiuntivo dopo aver preso il lucchetto). Tuttavia, le raccolte non sono generalmente progettate per essere utilizzate in questo modo e la classe Dictionary incorporata è tra quelle che non dovrebbero mai essere lette e scritte contemporaneamente. –

+0

Grazie per questa grande spiegazione, Jeffrey! Avrei giurato con precisione che alcuni dei miei colleghi hanno già utilizzato un TryGetValue() prima e dopo il lock() della raccolta. Questo potrebbe essere stato un cattivo utilizzo da parte loro allora. Grazie! Lo ricorderò. =) –

3

Nessun problema qui, il blocco è rientrante dallo stesso thread. Ad esempio, non tutti gli oggetti di sincronizzazione hanno affinità di thread, semaforo. Ma Mutex e Monitor (lock) vanno bene.

Problemi correlati