Je comprends que le mutex récursif permet au mutex d'être verrouillé plus d'une fois sans arriver à une impasse et devrait être déverrouillé le même nombre de fois. Mais dans quelles situations spécifiques avez-vous besoin d'utiliser un mutex récursif? Je recherche des situations de conception/niveau de code.
Par exemple, lorsque vous avez une fonction qui l'appelle récursivement et que vous souhaitez obtenir un accès synchronisé à celle-ci:
void foo() {
... mutex_acquire();
... foo();
... mutex_release();
}
sans mutex récursif, vous devez d'abord créer une fonction de "point d'entrée", ce qui devient lourd lorsque vous disposez d'un ensemble de fonctions mutuellement récursives. Sans mutex récursif:
void foo_entry() {
mutex_acquire(); foo(); mutex_release(); }
void foo() { ... foo(); ... }
Les mutex récursifs et non récursifs ont différents cas d'utilisation. Aucun type de mutex ne peut facilement remplacer l'autre. Les mutex non récursifs ont moins de surcharge, et les mutex récursifs ont dans certaines situations une sémantique utile ou même nécessaire et dans d'autres situations une sémantique dangereuse ou même brisée. Dans la plupart des cas, quelqu'un peut remplacer toute stratégie utilisant des mutex récursifs par une stratégie différente, plus sûre et plus efficace, basée sur l'utilisation de mutex non récursifs.
Si vous voulez voir un exemple de code qui utilise des mutex récursifs, regardez les sources de "Electric Fence" pour Linux/Unix. 'C'était l'un des outils Unix courants pour trouver des "dépassements et des sous-exécutions" de vérification des limites "en lecture/écriture ainsi que pour utiliser la mémoire qui a été libérée, avant Valgrind .
Compilez et liez simplement la clôture électrique avec les sources (option -g avec gcc/g ++), puis liez-la avec votre logiciel avec l'option de lien -lefence, et commencez à passer à travers les appels à malloc/free. http://elinux.org/Electric_Fence
J'ai rencontré le besoin d'un mutex récursif aujourd'hui, et je pense que c'est peut-être l'exemple le plus simple parmi les réponses publiées jusqu'à présent: il s'agit d'une classe qui expose deux fonctions API, Process (...) et reset ().
public void Process(...)
{
acquire_mutex(mMutex);
// Heavy processing
...
reset();
...
release_mutex(mMutex);
}
public void reset()
{
acquire_mutex(mMutex);
// Reset
...
release_mutex(mMutex);
}
Les deux fonctions ne doivent pas s'exécuter simultanément car elles modifient les internes de la classe, j'ai donc voulu utiliser un mutex. Le problème est que Process () appelle reset () en interne, et cela créerait un blocage car mMutex est déjà acquis. Les verrouiller avec un verrou récursif résout plutôt le problème.
Ce serait certainement un problème si un thread bloqué essayait d'acquérir (encore) un mutex qu'il possédait déjà ...
Y a-t-il une raison pour ne pas permettre qu'un mutex soit acquis plusieurs fois par le même thread?