Das Was und Warum von rekursivem Mutex sollte nicht so kompliziert sein, wie in der akzeptierten Antwort beschrieben.
Ich möchte mein Verständnis nach einigem Stöbern im Netz aufschreiben.
Zunächst sollten Sie sich darüber im Klaren sein, dass bei der Diskussion über Mutex definitiv auch Multithread-Konzepte eine Rolle spielen. (Mutex wird für die Synchronisation verwendet. Ich brauche keinen Mutex, wenn ich nur 1 Thread in meinem Programm habe.)
Zweitens sollten Sie den Unterschied zwischen einem normalen Mutex und einem rekursiven Mutex kennen .
Zitiert aus APUE :
(Ein rekursiver Mutex ist a) Ein Mutex-Typ, mit dem derselbe Thread ihn mehrmals sperren kann, ohne ihn zuvor zu entsperren.
Der Hauptunterschied besteht darin, dass das erneute Sperren einer rekursiven Sperre innerhalb desselben Threads weder zu einem Deadlock führt noch den Thread blockiert.
Bedeutet dies, dass ein Recusive Lock niemals einen Deadlock verursacht?
Nein, es kann immer noch zu einem Deadlock als normalem Mutex führen, wenn Sie ihn in einem Thread gesperrt haben, ohne ihn zu entsperren, und versuchen, ihn in anderen Threads zu sperren.
Sehen wir uns einen Code als Beweis an.
- normaler Mutex mit Deadlock
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t lock;
void * func1(void *arg){
printf("thread1\n");
pthread_mutex_lock(&lock);
printf("thread1 hey hey\n");
}
void * func2(void *arg){
printf("thread2\n");
pthread_mutex_lock(&lock);
printf("thread2 hey hey\n");
}
int main(){
pthread_mutexattr_t lock_attr;
int error;
// error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_DEFAULT);
if(error){
perror(NULL);
}
pthread_mutex_init(&lock, &lock_attr);
pthread_t t1, t2;
pthread_create(&t1, NULL, func1, NULL);
pthread_create(&t2, NULL, func2, NULL);
pthread_join(t2, NULL);
}
Ausgabe:
thread1
thread1 hey hey
thread2
häufiges Deadlock-Beispiel, kein Problem.
- rekursiver Mutex mit Deadlock
Kommentieren Sie diese Zeile einfach aus
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
Kommentieren Sie und kommentieren Sie die andere aus.
Ausgabe:
thread1
thread1 hey hey
thread2
Ja, rekursiver Mutex kann auch einen Deadlock verursachen.
- normaler Mutex, im selben Thread erneut sperren
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
pthread_mutex_t lock;
void func3(){
printf("func3\n");
pthread_mutex_lock(&lock);
printf("func3 hey hey\n");
}
void * func1(void *arg){
printf("thread1\n");
pthread_mutex_lock(&lock);
func3();
printf("thread1 hey hey\n");
}
void * func2(void *arg){
printf("thread2\n");
pthread_mutex_lock(&lock);
printf("thread2 hey hey\n");
}
int main(){
pthread_mutexattr_t lock_attr;
int error;
// error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_DEFAULT);
if(error){
perror(NULL);
}
pthread_mutex_init(&lock, &lock_attr);
pthread_t t1, t2;
pthread_create(&t1, NULL, func1, NULL);
sleep(2);
pthread_create(&t2, NULL, func2, NULL);
pthread_join(t2, NULL);
}
Ausgabe:
thread1
func3
thread2
Deadlock in thread t1
, in func3
.
(Ich benutze es sleep(2)
, um leichter zu erkennen, dass der Deadlock zuerst durch erneutes Sperren verursacht wird. func3
)
- rekursiver Mutex, im selben Thread erneut sperren
Kommentieren Sie erneut die rekursive Mutex-Zeile aus und kommentieren Sie die andere Zeile aus.
Ausgabe:
thread1
func3
func3 hey hey
thread1 hey hey
thread2
Deadlock in thread t2
, in func2
. Sehen? func3
Wird beendet und beendet, blockiert das erneute Verriegeln nicht den Faden oder führt zu einem Deadlock.
Letzte Frage, warum brauchen wir das?
Für rekursive Funktionen (wird in Multithread-Programmen aufgerufen und Sie möchten einige Ressourcen / Daten schützen).
Beispiel: Sie haben ein Multithread-Programm und rufen in Thread A eine rekursive Funktion auf. Sie haben einige Daten, die Sie in dieser rekursiven Funktion schützen möchten, und verwenden daher den Mutex-Mechanismus. Die Ausführung dieser Funktion erfolgt sequentiell in Thread A, sodass Sie den Mutex definitiv in Rekursion erneut sperren würden. Die Verwendung von normalem Mutex führt zu Deadlocks. Und resursiver Mutex erfunden, um dies zu lösen.
Sehen Sie sich ein Beispiel aus der akzeptierten Antwort an.
Wann wird rekursiver Mutex verwendet? .
Die Wikipedia erklärt den rekursiven Mutex sehr gut. Auf jeden Fall eine Lektüre wert. Wikipedia: Reentrant_mutex