2012-02-13 7 views
7

Mam generic Queue<T> (System.Collections.Generic), który jest dostępny do pisania z jednego wątku. I musi być dostępny z innego wątku do czytania.Czy kopiowanie całej kolejki <T> z operatorem "=" bezpieczne wątku (C#)

Nie chcę wykonywać żadnej synchronizacji procesu (która obejmuje używanie ConcurrentQueue<T>) ze względu na wydajność. Więc wpadłem na pomysł, aby skopiować całą kolejkę do innego obiektu kolejki tego samego typu w wątku do czytania. Kolejne operacje w wątku do czytania będą wykonywane na kopii. Kopiowanie zostanie wykonane za pomocą prostego operatora =.

Oto niektóre pseudo-code:

//Creating main queue 
Queue<MyType> queue1 = new Queue<MyType>(); 

Pisanie Temat:

//Perform writing in the main queue 
queue1.Enqueue(object); 
... 
queue1.Dequeue(); 

Czytając wątek:

//Copy main queue 
Queue<MyType> queue2 = queue1; 
//perform all operations in reading thread on queue2 

Więc jest taki wątek rozwiązanie jest bezpieczne?

UPD: Dziękuję bardzo, nie wiedziałem, że to tylko kopiowanie linku. Czy istnieje sposób na skopiowanie całego obiektu według wartości w sposób bezpieczny dla wątków?

+0

Wątek jest bezpieczny tylko wtedy, gdy nie zmienisz kolejki po opublikowaniu go w innym wątku. – Steven

+0

Zwykle "Kolejka" ma być używana w scenariuszu producent/konsument. Np. Jeden wątek pisze do niego, a drugi czyta z niego. Nie ma sensu kopiowanie go za każdym razem (można użyć dowolnego typu kolekcji i będzie działać tak samo). Powinieneś użyć pojedynczej kolejki współdzielonej i zablokować ją zaraz po odłożeniu pojedynczego elementu lub użyć 'ConcurrentQueue', jak to opisano poniżej. – Groo

Odpowiedz

11

Queue<T> to typ odniesienia. Dlatego przypisanie wartości queue1 do queue2 powoduje skopiowanie tylko odwołania, a nie samej kolejki.

Samo zadanie jest atomowe, a tym samym bezpieczne dla wątków. Uzyskiwanie dostępu do queue1 w jednym wątku i queue2 w innym wątku nie jest bezpieczniejsze, ponieważ uzyskują dostęp do queue1 od nich obu. tj. jest niebezpieczne.

Wierzę, że ConcurrentQueue<T> używa technik programowania "bez blokady" (Interlocked.Exchange i przyjaciół) i jest dość szybki. Powinieneś najpierw go porównać, zanim go wykluczysz jako rozwiązanie.

Kopiowanie Queue<T> będzie z pewnością wolniejsze niż użycie tylko ConcurrentQueue<T>.


W moim systemie 2.6 GHz ConcurrentQueue<object> zarządza 15 milionów par enqueue/rozkolejkowania na sekundę w porównaniu do 40 milionów zz Queue<object>. Tak więc Queue<object> jest około trzy razy szybciej.

200 Cykle procesora dla pary typu "kolejka"/"pseudo" są dość tanie. Jeśli jest to wąskie gardło, spróbuj użyć bardziej ziarnistych elementów w kolejce.

+0

To jest informacyjne. Dzięki! –

1

Krótka odpowiedź - nie, nie jest bezpieczna dla wątków.

Pamiętaj, że nie kopiujesz samej kolejki: kopiujesz odniesienie do pojedynczej kolejki. (Przypisanie referencji ma charakter atomowy, więc linia queue2 = queue1 nie jest problemem, a następnie robi to z kolejką, która w ogóle nie jest bezpieczna dla wątków.)

2

To nie kopiuje instancji Queue. Kopiuje tylko samo odniesienie.Kopiowanie odniesienia jest atomowe, ale nowe odwołanie będzie nadal wskazywać na to samo wystąpienie. Modyfikowanie instancji z wielu wątków jest , a nie bezpieczne dla wątków bez synchronizacji.

0

Kopiowanie kolekcji w ten sposób spowoduje tylko płytką kopię obiektu. Oznacza to, że skopiuje tylko odniesienie do tej samej kolejki. To jest bezpieczne dla wątków.

Jeśli masz zamiar zrobić głęboką kopię. Zobacz: this post może pomóc w wykonaniu głębokiej kopii obiektu. Chociaż @CodeInChaos ma naprawdę dobry punkt. Kopiowanie całego obiektu w ten sposób z pewnością będzie wolniejsze niż po prostu używanie ConcurentQueue<T>.

+1

Ten rodzaj głębokiej kopii jest bardzo brzydki. I jest to z pewnością wolniejsze niż użycie 'ConcurrentQueue '. – CodesInChaos

+0

@CodeInChaos - Wiem, ale myślę, że wspomniał w swoim poście, że nie chce używać ConcurrentQueue , dlatego nie sugerowałem tego. – TheBoyan

0

Oto co MSDN ma do powiedzenia na temat bezpieczeństwa wątku:

kolejce może obsługiwać wiele czytelników jednocześnie, dopóki kolekcja nie jest modyfikowany. Mimo to wyliczenie poprzez kolekcję samoistnie nie jest procedurą bezpieczną dla wątków. Aby zagwarantować bezpieczeństwo wątków podczas wyliczania, możesz zablokować kolekcję podczas całego wyliczania. Aby umożliwić dostęp do kolekcji przez wiele wątków do czytania i pisania, musisz zaimplementować własną synchronizację.

Powiązane problemy