El qué y el por qué del mutex recursivo no debería ser algo tan complicado como se describe en la respuesta aceptada.
Me gustaría anotar mi entendimiento después de investigar un poco en la red.
Primero, debe darse cuenta de que cuando se habla de mutex , los conceptos de subprocesos múltiples definitivamente también están involucrados. (mutex se usa para la sincronización. No necesito mutex si solo tengo 1 hilo en mi programa)
En segundo lugar, debe conocer la diferencia entre un mutex normal y un mutex recursivo .
Citado de APUE :
(Un mutex recursivo es a) Un tipo de mutex que permite que el mismo hilo lo bloquee varias veces sin desbloquearlo primero.
La diferencia clave es que dentro del mismo hilo , volver a bloquear un bloqueo recursivo no conduce a un punto muerto ni bloquea el hilo.
¿Significa esto que el bloqueo recusivo nunca provoca un interbloqueo?
No, todavía puede causar interbloqueo como mutex normal si lo ha bloqueado en un hilo sin desbloquearlo e intenta bloquearlo en otros hilos.
Veamos un código como prueba.
- mutex normal con interbloqueo
#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);
}
salida:
thread1
thread1 hey hey
thread2
ejemplo común de interbloqueo, no hay problema.
- mutex recursivo con interbloqueo
Simplemente descomente esta línea
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
y comente la otra.
salida:
thread1
thread1 hey hey
thread2
Sí, el mutex recursivo también puede causar un punto muerto.
- mutex normal, volver a bloquear en el mismo hilo
#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);
}
salida:
thread1
func3
thread2
Deadlock in thread t1
, in func3
.
(Utilizo sleep(2)
para que sea más fácil ver que el interbloqueo se debe en primer lugar a la reubicación func3
)
- mutex recursivo, volver a bloquear en el mismo hilo
De nuevo, descomente la línea recursiva mutex y comente la otra línea.
salida:
thread1
func3
func3 hey hey
thread1 hey hey
thread2
Deadlock in thread t2
, in func2
. ¿Ver? func3
termina y sale, el rebloqueo no bloquea el hilo ni conduce a un punto muerto.
Entonces, última pregunta, ¿por qué la necesitamos?
Para función recursiva (llamada en programas multiproceso y desea proteger algunos recursos / datos).
Por ejemplo, tiene un programa de varios subprocesos y llama a una función recursiva en el subproceso A. Tiene algunos datos que desea proteger en esa función recursiva, por lo que utiliza el mecanismo mutex. La ejecución de esa función es secuencial en el subproceso A, por lo que definitivamente volvería a bloquear el mutex en recursividad. El uso de mutex normal provoca interbloqueos. Y se inventa el mutex resursivo para resolver esto.
Vea un ejemplo de la respuesta aceptada ¿
Cuándo usar mutex recursivo? .
Wikipedia explica muy bien el mutex recursivo. Definitivamente vale la pena leerlo. Wikipedia: Reentrant_mutex