2013-06-07 14 views
6

Mam wiele kolejek, do których dostęp ma wiele wątków. Aby osiągnąć wątku bezpieczeństwa, zrobiłem co następuje:Czy mogę używać elementów słownika jako obiektów blokujących?

private static Dictionary<string, Queue<string>> MyQueues = new Dictionary<string, Queue<string>>(); 

public static string GetNextQueueElementForKey(string key) 
{ 
    string res = string.Empty; 

    if (MyQueues.Keys.Contains(key)) 
    { 
     Queue<string> queue = MyQueues[key]; 
     lock (queue) 
     { 
      if (queue.Count() > 0) 
      { 
       res = queue.Dequeue(); 
      } 
     } 
    } 

    return res; 
} 

mogę również zablokować MyQueues, ale potem chciałbym zablokować więcej niż to konieczne. Moje pytanie brzmi, czy blokowanie obiektu zawartego w słowniku będzie działało - zakładając, że wartość klucza (kolejka) nigdy się nie zmieni.

+0

Twoje pytanie brzmi bardziej jak wypowiedź. Jakie jest twoje pytanie? –

+0

Nie blokujesz obiektów, blokujesz * odniesienia do obiektów *. Innymi słowy, zmiana wartości obiektu nie wpływa na blokadę. – Nolonar

+0

@Nolonarnie, blokujesz sam obiekt. Możesz mieć 17 odniesień do tego samego obiektu - oni wszyscy zablokują to samo. –

Odpowiedz

6

You może - ale ogólnie nie byłby. Osobiście zwykle próbuję blokować zwykłe instancje System.Object, które nie są używane do niczego innego, i najlepiej nie są wystawione na żaden inny kod niż blokowanie klasy. W ten sposób możesz być absolutnie pewny, że nic więcej się nie zablokuje.

W tym przypadku wygląda na to, że masz kontrolę nad kolejek więc wiesz, że nie będzie używany przez inny kod, ale to możliwe że kod wewnątrz Queue<T> zablokuje na this. Prawdopodobnie tak nie jest, ale o to się martwię.

Zasadniczo, chciałbym, aby .NET nie zastosował podejścia Java do "monitora dla każdego obiektu" - szkoda, że ​​Monitor nie był klasą, którą można wpisać.

(zakładam, że jesteś tylko faktycznie czytanie ze słownika z wielu wątków? To nie jest bezpieczne w użyciu słowników dla wielowątkowych odczytu/zapisu.)

+0

Zapisuję tylko do kolejki, gdy jest pusta. Pominąłem tę część w powyższym kodzie dla uproszczenia. Ale kolejka powinna być w tym przypadku zablokowana, więc pisanie do niej nie powinno sprawiać żadnych problemów. – Ben

+1

Ale używanie zwykłego 'System.Object' nie działa dla nieznanej liczby obiektów blokujących. – Ben

+0

@Ben: Można użyć słownika dedykowanych obiektów blokady, po jednym dla każdej instancji 'Kolejka '. Wciąż nie rozumiem, dlaczego używasz 'Queue ' zamiast ['ConcurrentQueue '] (http://stackoverflow.com/a/16984743/45914). – jason

2

Fakt, że jest to element w słownik jest w dużej mierze nieistotny - pod warunkiem, że jest to typ odniesienia (który jest). Każda kolejka, po pobraniu ze słownika, będzie za każdym razem tą samą instancją, co object. Oznacza to, że będzie działał idealnie rozsądnie z blokowaniem na poziomie kolejki.

W zasadzie: tak, to powinno działać dobrze - o ile Enqueue robi to samo blokowanie za kolejkę. Jak zauważa Jon - czy to powinno być czy to jest inne pytanie.

Osobiście jestem nadal zdania, że ​​Monitor powinien być typu nie statycznego, i że można zablokować tylko instancje Monitor, a nie jakikolwiek object.

1

Moje pytanie brzmi, czy blokowanie obiektu zawartego w słowniku będzie działało - przy założeniu, że wartość klucza (kolejka) nigdy się nie zmieni.

Patrząc na kod tutaj:

lock (queue) { 
    if (queue.Count() > 0) { 
     res = queue.Dequeue(); 
    } 
} 

Ty może, ale chciałbym nie to zrobić. Powinieneś być never lock on the object itself, ponieważ możesz konkurować z innymi wątkami kodu, który zablokuje się na tym samym obiekcie, w tym samym Queue<T> (który może zablokować na this).

Powinieneś utworzyć co najmniej dedykowany obiekt blokady dla każdej kolejki.

Ale czy istnieje powód, dla którego nie używasz ConcurrentQueue<T>? To byłoby najprostsze rozwiązanie i przeniesienie ciężaru związanego z dostosowaniem go do Ramy.

Powiązane problemy