rentrants verrouillage
Serrure rentrante est celui où un processus peut demander le verrouillage à plusieurs reprises sans bloquer sur lui-même. C'est utile dans les situations où il n'est pas facile de savoir si vous avez déjà saisi un verrou. Si un verrou n'est pas rentrant, vous pouvez saisir le verrou, puis le bloquer lorsque vous le reprenez, ce qui bloque votre propre processus.
La réentrance en général est une propriété du code où elle n'a pas d'état mutable central qui pourrait être corrompu si le code était appelé pendant son exécution. Un tel appel pourrait être fait par un autre thread, ou il pourrait être fait récursivement par un chemin d'exécution provenant de l'intérieur du code lui-même.
Si le code repose sur un état partagé qui pourrait être mis à jour au cours de son exécution, il n'est pas re-entrant, du moins pas si cette mise à jour pouvait le casser.
Un cas d'utilisation pour le verrouillage rentrante
Un exemple d'une application (un peu générique et artificielle) pour un verrou rentrante pourrait être:
Vous avez un calcul impliquant un algorithme qui traverse un graphe (peut-être avec des cycles). Une traversée peut visiter le même nœud plus d'une fois en raison des cycles ou en raison de plusieurs chemins vers le même nœud.
La structure de données est soumise à un accès concurrent et pourrait être mise à jour pour une raison quelconque, peut-être par un autre thread. Vous devez être en mesure de verrouiller des nœuds individuels pour faire face à la corruption de données potentielles en raison des conditions de course. Pour une raison quelconque (peut-être la performance), vous ne voulez pas verrouiller globalement toute la structure de données. Votre calcul ne peut pas conserver des informations complètes sur les nœuds que vous avez visités, ou vous utilisez une structure de données qui ne permet pas de répondre rapidement aux questions «Ai-je été ici avant»?
Un exemple de cette situation serait une implémentation simple de l'algorithme de Dijkstra avec une file d'attente prioritaire implémentée comme un tas binaire ou une recherche en largeur en utilisant une simple liste chaînée comme une file d'attente. Dans ces cas, l'analyse de la file d'attente pour les insertions existantes est O (N) et vous ne voudrez peut-être pas le faire à chaque itération.
Dans cette situation, le suivi des verrous que vous avez déjà acquis est coûteux. En supposant que vous vouliez faire le verrouillage au niveau du nœud, un mécanisme de verrouillage de re-entrant atténue le besoin de dire si vous avez déjà visité un nœud auparavant. Vous pouvez verrouiller aveuglément le nœud, peut-être le déverrouiller après l'avoir retiré de la file d'attente.
mutex rentrants
Un mutex simple n'est pas rentrante comme un seul thread peut être dans la section critique à un moment donné. Si vous attrapez le mutex et que vous essayez de l'attraper à nouveau, un simple mutex n'a pas assez d'informations pour savoir qui le tenait auparavant. Pour ce faire récursivement, vous avez besoin d'un mécanisme où chaque thread a un jeton afin que vous puissiez dire qui a attrapé le mutex. Cela rend le mécanisme de mutex un peu plus cher, donc vous ne voudrez peut-être pas le faire dans toutes les situations.
IIRC l'API de threads POSIX offre l'option de mutex rentrants et non-rentrants.
Bien que de telles situations devraient généralement être évitées de toute façon, car il est également difficile d'éviter les interblocages. Threading est assez difficile de toute façon sans être dans le doute quant à savoir si vous avez déjà un verrou. –
+1, considérez également le cas où le verrou n'est pas réentrant, vous pouvez bloquer sur vous-même si vous ne faites pas attention. De plus, en C, vous n'avez pas les mêmes mécanismes que les autres langages pour s'assurer que le verrou est libéré autant de fois qu'il est acquis. Cela peut conduire à de gros problèmes. – user7116
c'est exactement ce qui m'est arrivé hier: je n'ai pas pris la question de la ré-entrée en considération et ai fini par déboguer une impasse pendant 5 heures ... – vehomzzz