Nadszedł czas na kolejną porcję przykładów z wykorzystaniem ThreadSafe collection.
W tym poscie po krótce opisze do czego i w jaki sposób używać kolekcji ConcurrentStack<T> oraz ConcurrentQueue<T>.
Kolelekcja ConcurrentStack<T> to typowa kolekcja LIFO (Last In First Out), ConcurrentQueue<T> jak się domyślacie to FIFO (Firt In Fist Out).
Jedyną zależnością pomiędzy kolekcjami Stack<T> i Queue<T> porównując je do opisywanych to taka, że my nie musimy się matrwić o wyjątki związane z dostępem do kolekcji z różnych wątków. ConcurrentStack<T> i ConcurrentQueue<T> załatwią to za nas 🙂
ConcurrentQueue<T> – najważniejsze metody, które powinny nas zainteresować to:
- Enqueue(T item) – metoda, która umożliwia dodanie nowego elementu do kolekcji
- TryPeek(out T item) – pobiera element z listy ale go nie usuwa
- TryDequeue(out T item) – metoda pobiera kolejny element z listy i automatycznie go z niej usuwa. Do tej metody musimy przekazać parametr wyjściowy takiego typu jakiego jest kolekcja. Jeżeli element znajduje się na liście metoda zwróci nam wartość true i nasz parametr wyjściowy będzie uzupełniony poprawną wartością. Jeżeli element nie zostanie znaleziony w kolekcji, metoda zwróci wartość false co będzie jednoznaczne z tym, że element nie został usunięty.
Patrząc dokładnie na to jak metoda wygląda w środku
|
1 2 3 4 5 6 7 8 9 10 11 |
[__DynamicallyInvokable] public bool TryDequeue(out T result) { while (!this.IsEmpty) { if (this.m_head.TryRemove(out result)) return true; } result = default (T); return false; } |
możemy zaobserwować rozwiązane, które musielibyśmy zaimplementować sami. Więc skoro dostajemy coś prosto z pudełka to lepiej zmienić nasze przyzwyczajenia i zmienić wykorzystywane w naszych projektach definicje stare obiekty na nowe 🙂
Więcej na temat tego czym jest m_head oraz metody TryRemove(out result) opiszę później.
Ta metoda jest właśnie tą, która odróżnia kolekcję Queue<T> od ConcurrentQueue<T>. (w kolekcji Queue<T> wywołujemy metodę Dequeue())
ConcurrentStack – 3 najważniejsze metody, które są wykorzystywane to:
– Push(T item)-dodaje element do kolekcji
– TryPop(out T item) – stara się pobrać element z listy i automatycznie go usuwa. Metoda zwraca true gdy usunie element z listy, false gdy elementu nie ma bądź nie mogł zostać usunięty.
– TryPeek(out T item) – pobiera e-ement z listy ale go nie usuwa
Chcąc przetoczyć przykład możemy wziąć ten sam, który był przedstawiony przeze mnie gdy opisywałem BlockingCollection.
Pierwszy przypadek, który można rozpatrzyć to po wypełnionej kolekcji pobieramy z niej elementy, które w poźniejszym etapie będziemy przerabiać.
Używając kolekcji Queue<T> lub Stack<T> możemy trafić na trywialne problemy jakimi mogą być:
- wątek chce przetwazać informacje na elemencie, którego w kolekcji już nie ma

- kolekcja jest już pusta a my chcemy pobrać jeszcze jakiś element

Zmiana Queue<T> na ConcurrentQueue<T> spowoduje to, że wcześniej opisane problemy nie będą miały prawa wystąpić.
Dokładnie to samo dotyczy kolekcji Stack<T> oraz ConcurrentStack<T> z tym wyjątkiem, że kedna z nich to FIFO a druga to LIFO.
Przykład jak zwykle znajdziecie na github 🙂

