Voir diverses questions liées au verrouillage et (presque) toujours trouver la `` boucle à cause de termes de réveils parasites '' 1 Je me demande, quelqu'un a-t-il connu un tel type de réveil (en supposant un environnement matériel / logiciel décent par exemple)?
Je sais que le terme «faux» ne signifie aucune raison apparente, mais quelles peuvent être les raisons d'un tel type d'événement?
( 1 Remarque: je ne remets pas en question la pratique du bouclage.)
Edit: Une question d'aide (pour ceux qui aiment les échantillons de code):
Si j'ai le programme suivant et que je l'exécute:
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();
}
}
}
Que puis-je faire pour réveiller cela await
de manière fallacieuse sans attendre indéfiniment un événement aléatoire?
java
multithreading
locking
spurious-wakeup
akarnokd
la source
la source
pthread_cond_wait()
la vraie question est "Pourquoi pthread_cond_wait a-t-il des réveils parasites?" .Réponses:
L' article de Wikipedia sur les réveils parasites a ce petit mot :
Résumé : si un processus Linux est signalé, ses threads en attente bénéficieront chacun d'un réveil parasite à chaud .
Je l'achète. C'est une pilule plus facile à avaler que la raison généralement vague «c'est pour la performance» souvent invoquée.
la source
futex()
appel sous - jacent revientEINTR
, mais cette valeur de retour n'est pas propulsée au niveau suivant. L'appelant pthread doit donc rechercher un invariant. Ce qu'ils disent, c'est que lorsquepthread_cond_wait()
vous revenez, vous devez vérifier à nouveau l'état de votre boucle (invariant), car l'attente peut avoir été réveillée de manière erronée. La réception d'un signal pendant un appel système est une cause possible, mais ce n'est pas la seule.pthread
bibliothèque pourrait fournir son propre invariant et sa propre logique de vérification afin d'éliminer les réveils parasites, plutôt que de transmettre cette responsabilité à l'utilisateur. Cela aurait (vraisemblablement) l'impact revendiqué sur les performances.J'ai un système de production qui présente ce comportement. Un thread attend un signal indiquant qu'il y a un message dans la file d'attente. Dans les périodes de pointe, jusqu'à 20% des réveils sont parasites (c'est-à-dire quand il se réveille, il n'y a rien dans la file d'attente). Ce fil est le seul consommateur des messages. Il fonctionne sur un boîtier Linux SLES-10 à 8 processeurs et est construit avec GCC 4.1.2. Les messages proviennent d'une source externe et sont traités de manière asynchrone car il y a des problèmes si mon système ne les lit pas assez rapidement.
la source
Répondre à la question du titre - Oui! Bien que l' article du Wiki mentionne beaucoup de choses sur les réveils parasites, une belle explication pour la même chose que j'ai rencontrée est la suivante -
Je lisais cette réponse de Source et je l'ai trouvée assez raisonnable. Lisez aussi
Réveils parasites en Java et comment les éviter .
PS: Le lien ci-dessus est vers mon blog personnel qui contient des détails supplémentaires sur les réveils parasites.
la source
Cameron Purdy a écrit un billet de blog il y a quelque temps sur le fait d'avoir été frappé par un faux problème de réveil. Alors oui, ça arrive
Je suppose que c'est dans la spécification (comme une possibilité) en raison des limitations de certaines des plates-formes sur lesquelles Java est déployé? bien que je puisse me tromper!
la source
Juste pour ajouter ceci. Oui, cela se produit et j'ai passé trois jours à rechercher la cause d'un problème de multi-thread sur une machine à 24 cœurs (JDK 6). 4 exécutions sur 10 ont connu cela sans aucun schéma. Cela ne s'est jamais produit sur 2 cœurs ou 8 cœurs.
A étudié du matériel en ligne et ce n'est pas un problème Java mais un comportement général rare mais attendu.
la source
https://stackoverflow.com/a/1461956/14731 contient une excellente explication des raisons pour lesquelles vous devez vous prémunir contre les réveils parasites même si le système d'exploitation sous-jacent ne les déclenche pas. Il est intéressant de noter que cette explication s'applique à plusieurs langages de programmation, y compris Java.
la source
Répondre à la question du PO
, aucun réveil parasite ne pourrait réveiller ce fil en attente!
Indépendamment du fait que des réveils parasites peuvent ou non se produire sur une plate-forme particulière, dans le cas de l'extrait de l'OP, il est absolument impossible pour
Condition.await()
revenir et de voir la ligne « Spurious réveil! » dans le flux de sortie.Sauf si vous utilisez une bibliothèque de classes Java très exotique
En effet, la méthode standard d' OpenJDK renvoie l' implémentation d' interface imbriquée (soit dit en passant, c'est la seule implémentation d' interface dans cette bibliothèque de classes) et la méthode elle-même vérifie si la condition ne les prises et aucun réveil parasite ne pourraient forcer cette méthode à revenir par erreur.
ReentrantLock
newCondition()
AbstractQueuedSynchronizer
Condition
ConditionObject
Condition
ConditionObject
await()
Soit dit en passant, vous pouvez le vérifier vous-même car il est assez facile d'émuler un réveil parasite une fois que l'
AbstractQueuedSynchronizer
implémentation basée est impliquée.AbstractQueuedSynchronizer
utilise à faible niveauLockSupport
depark
etunpark
méthodes, et si vous invoquezLockSupport.unpark
sur un fil en attente surCondition
, cette action ne peut être distingué d'un réveil parasite.Refactorisant légèrement l'extrait de l'OP,
, et quelle que soit la force avec laquelle le thread non principal (principal) tentera de réveiller le thread en attente, la
Condition.await()
méthode ne reviendra jamais dans ce cas.Les faux réveils sur
Condition
les méthodes en attente de sont discutés dans le javadoc de l'Condition
interface . Bien qu'il le dise,et cela
mais il ajoute plus tard que
et
AbstractQueuedSynchronizer
l'implémentation de l'Condition
interface fait exactement cela - supprime toute possibilité de réveils parasites .Cela vaut certainement pour les autres
ConditionObject
méthodes en attente.Alors le conclusion est:
nous devons toujours appeler
Condition.await
dans la boucle et vérifier si la condition ne tient pas, mais avec OpenJDK standard, la bibliothèque de classes Java ne peut jamais se produire . Sauf si, encore une fois, vous utilisez une bibliothèque de classes Java très inhabituelle (qui doit être très inhabituelle, car une autre bibliothèque de classes Java non OpenJDK bien connue, actuellement presque éteinte GNU Classpath et Apache Harmony , semble identique à l'implémentation standard de l'Condition
interface)la source