Il cosa e il perché del mutex ricorsivo non dovrebbe essere una cosa così complicata descritta nella risposta accettata.
Vorrei scrivere la mia comprensione dopo aver scavato un po 'intorno alla rete.
Innanzitutto, dovresti capire che quando si parla di mutex , anche i concetti multi thread sono sicuramente coinvolti. (mutex viene utilizzato per la sincronizzazione. Non ho bisogno di mutex se ho solo 1 thread nel mio programma)
In secondo luogo, dovresti conoscere la differenza tra un mutex normale e un mutex ricorsivo .
Citato da APUE :
(Un mutex ricorsivo è a) Un tipo di mutex che consente allo stesso thread di bloccarlo più volte senza prima sbloccarlo.
La differenza fondamentale è che all'interno dello stesso thread , il blocco di un blocco ricorsivo non porta a un deadlock, né blocca il thread.
Ciò significa che il blocco recusivo non causa mai un deadlock?
No, può ancora causare deadlock come un normale mutex se lo hai bloccato in un thread senza sbloccarlo e provi a bloccarlo in altri thread.
Vediamo del codice come prova.
- mutex normale con 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);
}
produzione:
thread1
thread1 hey hey
thread2
esempio comune di deadlock, nessun problema.
- mutex ricorsivo con deadlock
Basta rimuovere il commento da questa riga
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
e commentare l'altra.
produzione:
thread1
thread1 hey hey
thread2
Sì, anche il mutex ricorsivo può causare un deadlock.
- mutex normale, ribloccare nello stesso thread
#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);
}
produzione:
thread1
func3
thread2
Deadlock dentro thread t1
, dentro func3
.
(Io uso sleep(2)
per rendere più facile vedere che il deadlock è causato in primo luogo dal ribloccaggio func3
)
- mutex ricorsivo, blocca nuovamente nello stesso thread
Di nuovo, rimuovi il commento dalla riga mutex ricorsiva e commenta l'altra riga.
produzione:
thread1
func3
func3 hey hey
thread1 hey hey
thread2
Deadlock dentro thread t2
, dentro func2
. Vedere? func3
finisce ed esce, il ribloccaggio non blocca il thread o porta a un deadlock.
Quindi, ultima domanda, perché ne abbiamo bisogno?
Per la funzione ricorsiva (chiamata in programmi multi-thread e si desidera proteggere alcune risorse / dati).
Ad esempio, hai un programma multi thread e chiami una funzione ricorsiva nel thread A. Hai alcuni dati che vuoi proteggere in quella funzione ricorsiva, quindi usi il meccanismo mutex. L'esecuzione di quella funzione è sequenziale nel thread A, quindi bloccheresti sicuramente il mutex in ricorsione. Usa mutex normale causa deadlock. E il mutex risorsivo è stato inventato per risolvere questo problema.
Vedi un esempio dalla risposta accettata
Quando usare il mutex ricorsivo? .
La Wikipedia spiega molto bene il mutex ricorsivo. Sicuramente vale la pena leggere. Wikipedia: Reentrant_mutex