Widząc różne pytania związane z blokowaniem i (prawie) zawsze znajdując „pętlę z powodu fałszywych pobudek” 1 Zastanawiam się, czy ktoś doświadczył takiego rodzaju pobudki (na przykład zakładając przyzwoite środowisko sprzętowe / programowe)?
Wiem, że termin „fałszywy” oznacza brak wyraźnego powodu, ale jakie mogą być przyczyny takiego zdarzenia?
( 1 Uwaga: nie kwestionuję praktyki zapętlania.)
Edycja: pytanie pomocnicze (dla tych, którzy lubią próbki kodu):
Jeśli mam następujący program i uruchamiam go:
public class Spurious {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition cond = lock.newCondition();
lock.lock();
try {
try {
cond.await();
System.out.println("Spurious wakeup!");
} catch (InterruptedException ex) {
System.out.println("Just a regular interrupt.");
}
} finally {
lock.unlock();
}
}
}
Co mogę zrobić, aby obudzić to await
fałszywie, nie czekając wiecznie na przypadkowe wydarzenie?
java
multithreading
locking
spurious-wakeup
akarnokd
źródło
źródło
pthread_cond_wait()
prawdziwe pytanie brzmi: „Dlaczego pthread_cond_wait ma fałszywe budzenie?” .Odpowiedzi:
Artykuł w Wikipedii na temat fałszywych pobudek ma ten smakołyk:
Podsumowanie : Jeśli zasygnalizowany zostanie proces Linuksa, każdy z oczekujących wątków będzie cieszył się ładnym, gorącym fałszywym wybudzeniem .
Kupuję to. Jest to łatwiejsza pigułka do przełknięcia niż zwykle niejasny powód „z powodu wydajności”.
źródło
futex()
zwracaEINTR
, ale ta wartość zwracana nie jest przenoszona do następnego poziomu. Dzwoniący pthread musi zatem sprawdzić, czy nie ma niezmiennika. Mówią, że popthread_cond_wait()
powrocie musisz ponownie sprawdzić warunek pętli (niezmiennik), ponieważ oczekiwanie mogło zostać fałszywie przebudzone. Odbieranie sygnału podczas połączenia systemowego jest jedną z możliwych przyczyn, ale nie jedyną.pthread
biblioteka mogłaby dostarczać własny niezmiennik i własną logikę sprawdzania, aby wyeliminować fałszywe pobudki, zamiast przekazywać tę odpowiedzialność użytkownikowi. Miałoby to (prawdopodobnie) deklarowany wpływ na wydajność.Mam system produkcyjny, który wykazuje takie zachowanie. Wątek czeka na sygnał, że w kolejce jest komunikat. W okresach dużego ruchu do 20% pobudek jest fałszywych (tzn. Gdy się budzi, w kolejce nie ma nic). Ten wątek jest jedynym konsumentem wiadomości. Działa na 8-procesorowym systemie Linux SLES-10 i jest zbudowany z GCC 4.1.2. Wiadomości pochodzą z zewnętrznego źródła i są przetwarzane asynchronicznie, ponieważ występują problemy, jeśli mój system nie odczytuje ich wystarczająco szybko.
źródło
Aby odpowiedzieć na pytanie w tytule - Tak! tak się dzieje. Chociaż artykuł na Wiki wspomina sporo o fałszywych pobudkach, miłe wytłumaczenie tego, z czym się spotkałem, jest następujące:
Czytałem tę odpowiedź ze Źródła i uznałem ją za rozsądną. Przeczytaj także
Sztuczne budzenie w Javie i sposoby ich unikania .
PS: Powyższy link prowadzi do mojego osobistego bloga, który zawiera dodatkowe informacje na temat fałszywych pobudek.
źródło
Cameron Purdy napisał jakiś wpis na blogu o tym, że został trafiony przez fałszywy problem z pobudką. Tak więc się zdarza
Zgaduję, że jest w specyfikacji (jako możliwość) z powodu ograniczeń niektórych platform, na których Java jest wdrażana? chociaż mogę się mylić!
źródło
Po prostu to dodaj. Tak, zdarza się i spędziłem trzy dni na poszukiwaniu przyczyny problemu wielowątkowości na maszynie 24-rdzeniowej (JDK 6). 4 na 10 egzekucji doświadczyło tego bez żadnego wzorca. To się nigdy nie zdarzyło na 2 rdzeniach lub 8 rdzeniach.
Studiowałem trochę materiałów online i nie jest to problem związany z Javą, ale ogólne rzadkie, ale oczekiwane zachowanie.
źródło
https://stackoverflow.com/a/1461956/14731 zawiera doskonałe wyjaśnienie, dlaczego należy unikać fałszywych pobudek, nawet jeśli podstawowy system operacyjny ich nie wyzwala. Warto zauważyć, że to wyjaśnienie dotyczy wielu języków programowania, w tym Java.
źródło
Odpowiedź na pytanie PO
, żadne fałszywe budzenie nie mogłoby obudzić tego oczekującego wątku!
Niezależnie od tego, czy fałszywych wybudzeń może lub nie może się zdarzyć na danej platformie, w przypadku OP snippet to pozytywnie niemożliwe do
Condition.await()
powrotu i zobaczyć linię „Spurious wzbudzenia!” w strumieniu wyjściowym.Chyba że używasz bardzo egzotycznej biblioteki klas Java
To dlatego, że standard, openjdk „s
ReentrantLock
” s metodanewCondition()
zwracaAbstractQueuedSynchronizer
„s implementacjaCondition
interfejsu, zagnieżdżoneConditionObject
(nawiasem mówiąc, jest to jedyna realizacjaCondition
interfejsu w tej bibliotece klasy), aConditionObject
” s metodaawait()
sam sprawdza, czy warunek ten nie wstrzymanie i żadne fałszywe wybudzenie nie zmusiłoby tej metody do błędnego powrotu.Nawiasem mówiąc, możesz to sprawdzić sam, ponieważ bardzo łatwo jest emulować fałszywe wybudzanie po
AbstractQueuedSynchronizer
zaangażowaniu opartej na implementacji.AbstractQueuedSynchronizer
używa niskiego poziomuLockSupport
dydaktycznegopark
iunpark
metod, a jeśli wywołaszLockSupport.unpark
na nitce w oczekiwaniu naCondition
działanie to nie można odróżnić od fałszywych wznawianiu.Nieznacznie refaktoryzuje fragment OP,
, i bez względu na to, jak mocno wątek unparking (główny) próbowałby obudzić oczekujący wątek,
Condition.await()
metoda nigdy nie powróci w tym przypadku.Fałszywe pobudki
Condition
oczekujących metod są omówione w javadocCondition
interfejsu . Chociaż tak mówi,i to
ale później to dodaje
i
AbstractQueuedSynchronizer
implementacjaCondition
interfejsu robi dokładnie to - eliminuje wszelkie możliwości fałszywych pobudek .Z pewnością dotyczy to innych
ConditionObject
oczekujących metod.Tak więc wniosek jest:
zawsze powinniśmy wywoływać
Condition.await
pętlę i sprawdzać, czy warunek nie jest spełniony, ale przy standardowym OpenJDK biblioteka klas Java nigdy nie może się zdarzyć . Chyba że ponownie użyjesz bardzo nietypowej biblioteki klas Java (która musi być bardzo niezwykła, ponieważ inne dobrze znane biblioteki klas Java innej niż OpenJDK, obecnie prawie wymarłe GNU Classpath i Apache Harmony , wydają się mieć identyczną standardową implementacjęCondition
interfejsu)źródło