Ich verstehe, dass rekursiver Mutex das mehrfache Sperren von Mutex ermöglicht, ohne dass es zu einem Deadlock kommt, und dass er genauso oft entsperrt werden sollte. Aber in welchen speziellen Situationen müssen Sie einen rekursiven Mutex verwenden? Ich suche Situationen auf Design-/Code-Ebene.
Zum Beispiel, wenn Sie eine Funktion haben, die sie rekursiv aufruft, und Sie einen synchronisierten Zugriff darauf erhalten möchten:
void foo() {
... mutex_acquire();
... foo();
... mutex_release();
}
ohne einen rekursiven Mutex müssten Sie zuerst eine "Einstiegspunkt" -Funktion erstellen, und dies wird umständlich, wenn Sie eine Reihe von Funktionen haben, die gegenseitig rekursiv sind. Ohne rekursiven Mutex:
void foo_entry() {
mutex_acquire(); foo(); mutex_release(); }
void foo() { ... foo(); ... }
Rekursive und nicht-rekursive Mutexe haben verschiedene Anwendungsfälle. Kein Mutex-Typ kann den anderen leicht ersetzen. Nicht-rekursive Mutexe haben weniger Overhead und rekursive Mutexe haben in einigen Situationen nützliche oder sogar benötigte Semantik und in anderen Situationen gefährliche oder sogar gebrochene Semantik. In den meisten Fällen kann jemand eine Strategie mit rekursiven Mutexen durch eine andere sicherere und effizientere Strategie ersetzen, die auf der Verwendung von nicht rekursiven Mutexen basiert.
Wenn Sie ein Codebeispiel sehen möchten, das rekursive Mutexe verwendet, lesen Sie die Quellen für "Electric Fence" für Linux/Unix. Es war eines der gängigen Unix-Tools zum Auffinden von "Grenzen prüfen" von Lese-/Schreibüberschreitungen und -unterschreitungen sowie zum Verwenden von freigemachtem Speicher, bevor Valgrind auf den Markt kam.
Kompilieren und verknüpfen Sie einfach electric fence mit sources (Option -g mit gcc/g ++) und verknüpfen Sie es dann mit Ihrer Software mit der Verknüpfungsoption -lefence und beginnen Sie, die Aufrufe von malloc/free durchzugehen. http://elinux.org/Electric_Fence
Ich bin heute auf die Notwendigkeit eines rekursiven Mutex gestoßen, und ich denke, es ist das vielleicht einfachste Beispiel unter den bisher veröffentlichten Antworten: Dies ist eine Klasse, die zwei API-Funktionen bereitstellt, Process (...) und reset ().
public void Process(...)
{
acquire_mutex(mMutex);
// Heavy processing
...
reset();
...
release_mutex(mMutex);
}
public void reset()
{
acquire_mutex(mMutex);
// Reset
...
release_mutex(mMutex);
}
Beide Funktionen dürfen nicht gleichzeitig ausgeführt werden, da sie Interna der Klasse ändern. Daher wollte ich einen Mutex verwenden. Das Problem ist, dass Process () intern reset () aufruft und einen Deadlock erzeugt, da mMutex bereits erfasst wurde. Das Sperren mit einer rekursiven Sperre behebt das Problem.
Es wäre sicherlich ein Problem, wenn ein blockierter Thread versuchen würde, (erneut) einen Mutex zu erhalten, den er bereits besaß ...
Gibt es einen Grund, nicht zuzulassen, dass ein Mutex mehrmals von demselben Thread abgerufen wird?