2009-11-02 13 views
5

Załóżmy, że mam moduł z kolejką..NET - Czy wątek metody Queue.Enqueue jest bezpieczny?

przypadku innych podmiotów kolejkować, muszą przejść przez funkcję:

public sub InsertIntoQueue(Obj) 
    MyQueue.Enqueue(Obj) 
end sub 

Jeśli mam wiele wątków uruchomiony i chcą zadzwonić InsertIntoQueue(), jest to uważane wątek bezpieczne?

Mam wrażenie, że w pamięci jest tylko jedna kopia instrukcji potrzebnych do wykonania funkcji InsertIntoQueue() ... która mogłaby mnie przekonać, że jest to bezpieczne dla wątków.

Zastanawiam się jednak, co dzieje się, gdy dwa wątki próbują uruchomić funkcję w tym samym czasie?

Czy ten wątek jest bezpieczny, a jeśli nie, w jaki sposób mogę go zabezpieczyć? (i Jakie byłyby konsekwencje wydajności dotyczące prędkości i użycia pamięci)

Odpowiedz

4

Nie jest to bezpieczne dla wątków.

Elementy statyczne publiczne (udostępniane w języku Visual Basic) tego typu są bezpieczne dla operacji wielowątkowych. Członkowie instancji nie mają gwarancji, że są bezpieczni dla wątków.

Od MSDN Site.

Proponuję dodanie obiektu do reprezentowania synchronizacji uchwyt do obiektu

Dim SyncHandle as Object = new Object() 

i modyfikować swoje metody jako takiej

Public Sub InsertIntoQueue(Object item) 
    SyncLock SyncHandle 
     MyQueue.Enqueue(item) 
    End SyncLock 
End Sub 
1

Jeden zestaw instrukcji nie oznacza, że ​​jest bezpieczny dla wątków. Jeśli chodzi o instrukcje, zawsze masz tylko jeden zestaw.

Teraz, patrząc na dostarczony przykładowy kod, nie można stwierdzić, czy jest bezpieczny dla wątków, czy nie. Wszystkie standardowe kolekcje .NET, w tym kolejki, nie są same bezpieczne dla wątków, ale dają dostęp do zsynchronizowanej wersji.

Teraz w tłach wydajności, oczywiście jest hit wydajności, jak duży - to zależy od zakresu zamka i kilka innych rzeczy. W szczególności z wykorzystaniem globalnych blokad w aplikacji internetowej może stać się poważnym wąskim gardłem przy dużym obciążeniu

2

zrobić

SyncLock MyQueue 
    MyQueue.Enqueue(Obj) 
End SyncLock 

End Sub

0

Na ryzyko będzie nieco off topic PO za, należy rozważyć do innych metod kolejki. Zakładam, że istnieje co najmniej jeden obiekt odciągający wątek, i ewentualnie sprawdzasz również, czy kolejka jest pusta?

Z perspektywy usunięcia, jeśli posiadasz więcej niż jedno odciągnięcie nici i sprawdzają, czy kolejka nie jest pusta przed wywołaniem usunięcia z kolejki (aby zapobiec wyjątkowi nieważności operacji), to jest całkiem prawdopodobne, że jeden wątek (wątek a) może odłączyć ostatni element w kolejce, pomiędzy innym wątkiem (wątek b) odczytując, że kolejka nie jest pusta i wywołując usunięcie, a zatem wątek a spowoduje wyjątek dotyczący nieprawidłowej operacji.

Można zamknąć blokadę w celu sprawdzenia pustego i usunąć kolejkę, aby obejść to.

This i this są ciekawe artykuły na temat bezpieczeństwa wątku, a także mogę polecić czytanie this i/lub this, podczas gdy nie są one wszystkie w VB.NET Wyjaśniają gwintowania w szczegółach.

+0

Mój plan polegał na tym, że miałem wiele wątków, Enqueuing, i pojedynczy wątek blokujący i czyszczący całą kolejkę w określonych odstępach czasu. –

+0

Jeśli zablokujesz podczas przetwarzania wszystkich obiektów w kolejce, wszystkie wątki, które będą się zaklinowywać, będą blokowane (jeśli spróbują się zakodować) do momentu, w którym zakończona zostanie poprawiona kolejka, może lepiej zablokować tylko puste sprawdzanie i usuwanie z kolejki obiekt, a nie całe przetwarzanie kolejki. – Matt

0

Nie jestem ekspertem w zakresie bezpieczeństwa gwintów, ale staram się dowiedzieć jak najwięcej o tej sprawie.

Kiedyś myślałem (jak ty), że ta operacja może być bezpieczna dla wątków, ponieważ po prostu zapisuje dane w kolejce na różnych wątkach i nie ma potrzeby usuwania kolejki. Ale jak ktoś wyjaśnić tutaj (i jest wszędzie w dokumentacji MSDN):

publiczne statyczny (Shared w języku Visual Basic) członkami tego typu są bezpieczne dla operacji wielowątkowych . Wystąpienia członkowie nie mogą być wątkowo bezpieczne.

Oznacza to, że może wewnętrznie MyQueue.Enqueue(Obj) odbywa się to tak:

  1. dane umieścić na kolejce();
  2. Wskaźnik kolejki rozszerzenia;

Jeśli zostanie to zrobione w ten sposób, będziesz mieć problemy z wątkami, ponieważ jak widzisz, możesz zastąpić tę samą pozycję w kolejce dwoma wątkami, ponieważ jeden pisze po drugim zrobił to samo, ale to nie udało się już zwiększyć wskaźnik.

Mając to na uwadze, masz kilka opcji, jak tutaj wspomniano, blokowanie metody Enqueue(), użycie Queue.Synchronized() lub może nawet prostsze, ale z większym wpływem na wydajność, blokowanie właściwości prywatnej podczas uzyskiwania dostępu do kolejki obiekt w ten sposób (ponieważ wszystko, co robisz z Kolejką, nie będzie bezpieczne dla wątków):

Private ReadOnly Property MyQueue() as Queue 
Get 
    SyncLock (m_myQueueLock) 
     Return m_myQueue 
    EndSyncLock 
End Get 
End Property 

Mam nadzieję, że to pomoże!

Powiązane problemy