2010-03-09 14 views
10

Mam funkcję, która zwraca pozycję w słowniku, na podstawie klucza (nazwa), a jeśli nie istnieje, zwraca nowo utworzony.Blokowanie słownika w obrębie tego samego wątku

Mam pytanie z "podwójnym zamkiem": SomeFunction blokuje _dictionary, aby sprawdzić istnienie klucza, a następnie wywołuje funkcję, która również blokuje ten sam słownik, wydaje się działać, ale nie jestem pewien jeśli istnieje potencjalny problem z tym podejściem.

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

Myślę, że nie rozumiesz, co robi blokowanie. Locking ** blokuje wszystkie inne wątki przed dostępem do chronionego regionu kodu **. Nie ma nic wspólnego z * bieżącym * wątkiem. Możesz wyjąć blokadę tysiąc razy na ten sam przedmiot na tej samej nitce, bez problemu; każdy region kodu zamknięty w ten sposób będzie chroniony przed dostępem innych wątków. –

+0

Jeśli szukasz "zamków w tym samym wątku", zajrzyj do klasy [Semaphore] (http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx). – ANeves

Odpowiedz

10

To gwarantowane działanie - blokady są rekurencyjne w .NET. Czy to naprawdę dobry pomysł, czy nie to inna sprawa ... jak to zamiast o:

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: Tylko po to, aby zweryfikować dla siebie, nie należy próbować uzyskiwać wartości zamiast blokować słownik od razu? Podobnie jak blokujesz tylko wtedy, gdy metoda TryGetValue() zwraca wartość false? –

+2

@Will Marcouiller - Twój schemat pozwoliłby jednemu wątkowi modyfikować słownik, podczas gdy inny wątek go czyta. Jeśli klasa słownika została specjalnie zaprojektowana, aby to umożliwić, to niektóre schematy wzdłuż tych linii mogą być możliwe (z dodatkową wartością TryGetValue po wykonaniu blokady). Jednak generalnie zbiory nie są zaprojektowane do tego, aby używać ich w ten sposób, a wbudowana klasa Dictionary jest jedną z tych, które nigdy nie powinny być czytane i pisane w tym samym czasie. –

+0

Dzięki za to wspaniałe wyjaśnienie Jeffrey! Przysiągłbym właśnie, że niektórzy z moich kolegów użyli już metody TryGetValue() przed i po zamknięciu() kolekcji. To mogło być z tego powodu złe. Dzięki! Będę o tym pamiętać. =) –

3

No Problem, blokada zostanie ponownie uczestnik tego samego wątku. Nie wszystkie obiekty synchronizacji mają powinowactwo do wątków, na przykład Semafor. Ale Mutex i Monitor (blokada) są w porządku.

Powiązane problemy