Une explication de réveil parasite ressemble à un bug qui ne vaut tout simplement pas la peine d'être corrigé, n'est-ce pas?

30

Selon l'article de Wikipedia sur Spurious Wakeups

"un thread peut être réveillé de son état d'attente même si aucun thread n'a signalé la variable de condition".

Bien que je connaisse cette `` fonctionnalité '', je n'ai jamais su ce qui l'a réellement provoquée jusqu'à ce que, dans le même article

"Des réveils parasites peuvent sembler étranges, mais sur certains systèmes multiprocesseurs, rendre le réveil des conditions complètement prévisible pourrait ralentir considérablement toutes les opérations de variables de conditions."

Cela ressemble à un bug qui ne mérite tout simplement pas d'être corrigé, n'est-ce pas?

James
la source
1
en relation: "Pourquoi pthread_cond_wait a-t-il de faux réveils?", stackoverflow.com/questions/8594591/…
Florian Castellane

Réponses:

39

TL; DR L' hypothèse («contrat») de réveils parasites est une décision architecturale judicieuse prise pour permettre des implémentations réalistes et robustes de la perte de fil.

Les "considérations de performances" ne sont pas pertinentes ici, ce ne sont que des malentendus qui se sont généralisés en raison de leur mention dans une référence officielle publiée. (Les références faisant autorité peuvent contenir des erreurs, vous savez - il suffit de demander à Galileo Galilei ) L' article de Wikipédia conserve la référence à la note que vous avez citée simplement parce qu'elle correspond parfaitement à leurs directives formelles de citer la référence publiée.

Une raison beaucoup plus convaincante pour introduire le concept de réveils parasites est fournie dans cette réponse à SO qui est basée sur des détails supplémentaires fournis dans une (ancienne version) de cet article:

L' article de Wikipédia sur les réveils parasites a cette friandise:

La pthread_cond_wait()fonction sous Linux est implémentée à l'aide de l' futexappel système. Chaque appel système bloquant sous Linux revient brusquement EINTRlorsque le processus reçoit un signal. ... pthread_cond_wait()ne peut pas redémarrer l'attente car il peut manquer un véritable réveil dans le peu de temps où il était en dehors de l' futexappel système ...

Pensez-y ... comme tout code, le planificateur de threads peut subir une panne temporaire en raison de quelque chose d'anormal qui se produit dans le matériel / logiciel sous-jacent. Bien sûr, il faut veiller à ce que cela se produise aussi rare que possible, mais comme il n'existe pas de logiciel 100% robuste, il est raisonnable de supposer que cela peut se produire et de veiller à la récupération gracieuse au cas où l'ordonnanceur le détecte (par exemple en observant les battements cardiaques manquants ).

Maintenant, comment l'ordonnanceur pourrait-il récupérer, en tenant compte du fait que pendant la panne, il pourrait manquer certains signaux destinés à notifier les threads en attente? Si le programmateur ne fait rien, les threads "malchanceux" mentionnés se bloqueront, attendant pour toujours - pour éviter cela, le programmateur enverrait simplement un signal à tous les threads en attente.

Il est donc nécessaire d'établir un "contrat" ​​selon lequel le thread en attente peut être notifié sans raison. Pour être précis, il y aurait une raison - le blackout de l'ordonnanceur - mais comme le thread est conçu (pour une bonne raison) pour ignorer les détails de l'implémentation interne de l'ordonnanceur, il est préférable de présenter cette raison comme "fausse".


Du point de vue du fil, cela ressemble un peu à une loi de Postel (aka principe de robustesse ),

soyez conservateur dans ce que vous faites, libéral dans ce que vous acceptez des autres

L'hypothèse de réveils parasites oblige le thread à être conservateur dans ce qu'il fait : définir la condition lors de la notification aux autres threads et libéral dans ce qu'il accepte : vérifier la condition à tout retour d'attente et répéter l'attente si elle n'est pas encore là.

moucheron
la source
10
Ugh ... La loi de Postel ... la raison pour laquelle le HTML et toutes sortes de technologies Web ont tellement de conneries (par exemple, l'acceptation HTML de l'imbrication de mauvaises balises). Cela mis à part, bonne réponse.
Thomas Eding
3
La loi de Postel est la raison pour laquelle de nombreux bugs restent inattendus pendant des années car bon, même si votre fonction renvoie la mauvaise sortie, l'application semble toujours fonctionner! Meilleure invention de tous les temps.
Pacerier
2
@Pacerier: la fonction renvoyant une mauvaise sortie ne suit pas la loi de Postel (partie conservatrice).
YvesgereY
@Pacerier: OTOH, exiger que les autres composants soient stricts pour que les bogues puissent être détectés plus tôt est une position intéressante, préférant le principe «Fail Fast» et la conception «Contract Based».
YvesgereY
1

Cela ne vaut pas la peine d'être corrigé, car le code de l'appelant devrait de toute façon utiliser le même traitement (vérifier la condition), afin de gérer la condition de concurrence.

Un traitement pour deux problèmes, que je résume comme suit:

Réveil parasite: un thread en attente est planifié avant que la condition ne soit établie.
Dépassement forcé: le thread en attente est planifié après que la condition a été falsifiée à nouveau.

Étant donné que cela pourrait arriver plus tard, certains sont allés jusqu'à introduire un réveil parasite dans le contrat:

  • appliquer les bonnes pratiques en exigeant des boucles de prédicat.
  • pour donner une certaine liberté pour l'implémentation du planificateur (y compris une option de récupération d'urgence, comme indiqué par @gnat).

Référence SO

YvesgereY
la source
Je voudrais attribuer +1 à cela, mais pour l'idée que quelqu'un a intentionnellement introduit des réveils parasites afin d'amener les appelants à ajouter des boucles de prédicat pour résoudre les dépassements de sommeil forcés. Je trouve cela inconcevable.
ruakh
«L'intention était de forcer un code correct / robuste en exigeant des boucles de prédicat.» Voir le lien fourni.
YvesgereY