2009-11-09 16 views
14

Supongamos que un proceso está creando un mutex en la memoria compartida y bloqueándolo y volcando el núcleo mientras el mutex está bloqueado.Mutex en memoria compartida cuando un usuario se bloquea?

Ahora en otro proceso, ¿cómo puedo detectar que el mutex ya está bloqueado pero no es propiedad de ningún proceso?

Respuesta

8

Si está trabajando en Linux o algo similar, considere el uso de named semaphores en lugar de (lo que supongo que son) pthreads mutex. No creo que haya una manera de determinar el PID de bloqueo de un mutex de pthreads, salvo crear tu propia tabla de registro y ponerla también en la memoria compartida.

+4

Estoy de acuerdo en general con la recomendación de semáforos, pero los semáforos POSIX realmente no resuelven el problema ya que tampoco registran el PID del proceso de bloqueo ni se desbloquean después de una muerte prematura. Rusty y torpe, aunque puedan ser semáforos SysV, hacen un seguimiento de los PID y pueden revertir cuando se los llama con la opción SEM_UNDO. – Duck

1

Debe utilizar un semáforo según lo provisto por el sistema operativo.

El sistema operativo libera todos los recursos que un proceso tiene abiertos, ya sea que muera o salga con elegancia.

+0

No en todos los recursos. Si OP usa el semáforo POSIX como se sugiere y el proceso que contiene el bloqueo muere, el valor del semáforo no se revertirá, lo que podría bloquear los otros procesos. – Duck

1

¡Dejé esta publicación INCORRECTA sin recuperar solo si alguien tiene la misma idea y encontrará esta discusión sobre el uso!


Puede usar este enfoque. 1) Bloquee el mutex compartido de POSIX 2) Guarde el id de proceso en la memoria compartida. 3) Desbloquear el mutex compartida 4) A la salida correcta limpiar el proceso-id

Si el proceso coredumps el próximo proceso dará cuenta de que en la memoria compartida no es un proceso de identificación guardado en el paso 2 #. Si no hay ningún proceso con este ID de proceso en el SO, entonces nadie posee el mutex compartido. Entonces solo es necesario reemplazar la identificación del proceso.

actualización con el fin de responder a los comentarios:

Escenario 1: 1. P1 comienza 2. P1 crea/abre un mutex llamado si no existe 3. P1 timed_locks el mutex llamado y exitosamente lo hace (espera 10 segundos si es necesario); 4. Predumps P1 5. P2 se inicia después del coredump 6. P2 crea/abre un mutex con nombre, existe, está OK 7. P2 timed_locks el mutex nombrado y no se bloquea (espera 10 segundos si es necesario); 8. P2 eliminar el mutex llamado 9. P2 recrea un mutex llamado & bloquearla

+0

No veo una solución aquí. Escenario 1: (1) bloqueos P1; (2) P1 muere; (3) punto muerto. Escenario 2: (1) bloqueos P1; (2) P1 escribe pid; (3) P1 se desbloquea; (4) P2 obtiene control y se bloquea y encuentra P1 pid. Escenario 3: si se cambia el orden para que el pid se borre antes del desbloqueo y el proceso muera, se vuelve al problema original de que el proceso muerto mantiene el bloqueo y bloquea los otros procesos. ¿Me estoy perdiendo de algo? – Duck

+0

Escenario comentado n. ° 1 –

+0

La actualización no es viable. La dependencia de un tiempo arbitrario es mala. Pero lo que es peor, si más de 1 proceso está intentando ejecutar esta fórmula, todo el infierno puede desatarse durante el tiempo de eliminar, volver a crear, bloquear, etc., el mutex. – Duck

5

¿Qué hay de bloqueo basado en archivos (usando flock(2))? Estos se liberan automáticamente cuando el proceso que lo contiene muere.

programa de demostración:

#include <stdio.h> 
#include <time.h> 
#include <sys/file.h> 

void main() { 
    FILE * f = fopen("testfile", "w+"); 

    printf("pid=%u time=%u Getting lock\n", getpid(), time(NULL)); 
    flock(fileno(f), LOCK_EX); 
    printf("pid=%u time=%u Got lock\n", getpid(), time(NULL)); 

    sleep(5); 
    printf("pid=%u time=%u Crashing\n", getpid(), time(NULL)); 
    *(int *)NULL = 1; 
} 

salida (He truncan los PIDs y los tiempos de un bit para mayor claridad):

$ ./a.out & sleep 2 ; ./a.out 
[1] 15 
pid=15 time=137 Getting lock 
pid=15 time=137 Got lock 
pid=17 time=139 Getting lock 
pid=15 time=142 Crashing 
pid=17 time=142 Got lock 
pid=17 time=147 Crashing 
[1]+ Segmentation fault  ./a.out 
Segmentation fault 

Lo que pasa es que el primer programa adquiere el bloqueo y se pone a duerme por 5 segundos. Después de 2 segundos, se inicia una segunda instancia del programa que bloquea al intentar adquirir el bloqueo. 3 segundos después, el primer programa segfaults (bash no te dice esto hasta más tarde) e inmediatamente, el segundo programa obtiene el bloqueo y continúa.

+0

No creo que se eliminará también, ya sea que sea archivo o memoria es lo mismo para ambos. – Vivek

+0

No me refiero a escribir algo dentro del archivo (que de hecho sería similar), sino a usar 'flock (2)'. Cuando su proceso muera, el archivo se cerrará automáticamente y se liberará el bloqueo. – Wim

+0

+1 solo esa bandada (fileno (f), LOCK_EX | LOCK_NB) es más seguro – dashesy

30

Parece que la respuesta exacta se ha proporcionado en forma de mutex robustos.

De acuerdo con POSIX, los mutexes pthread se pueden inicializar como "robustos" usando pthread_mutexattr_setrobust(). Si un proceso que contiene el mutex luego muere, el siguiente hilo para adquirirlo recibirá EOWNERDEAD (pero aún así obtendrá el mutex correctamente) para que sepa realizar cualquier limpieza. Luego debe notificar que el mutex adquirido es nuevamente consistente usando pthread_mutex_consistent().

Obviamente necesita compatibilidad con kernel y libc para que esto funcione. En Linux, el soporte del núcleo detrás de esto se llama "futexes robustos", y he encontrado referencias a actualizaciones de espacio de usuario que se aplican a glibc HEAD.

En la práctica, el soporte para esto no parece haberse filtrado todavía, al menos en el mundo de Linux. Si estas funciones no están disponibles, puede encontrar pthread_mutexattr_setrobust_np() en su lugar, que en lo que puedo deducir parece ser un predecesor no POSIX que proporciona la misma semántica. He encontrado referencias a pthread_mutexattr_setrobust_np() tanto en la documentación de Solaris como en /usr/include/pthread.h en Debian.

especificación POSIX se puede encontrar aquí: http://www.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setrobust.html

+3

Creo que esta es una mejor respuesta. He estado usando el mutex robusto en Solaris hasta ahora con éxito. –

+2

Los mutex robustos son geniales, pero tenga en cuenta que pueden no funcionar correctamente en GNU/Linux antes de glibc 2.15 si el mutex se creó en un proceso principal que luego se bifurca y el niño muere mientras mantiene el mutex. Ese [error] (http://sourceware.org/bugzilla/show_bug.cgi?id=13002) se corrigió en glibc 2.15. Si los dos procesos que comparten el mutex no son un elemento primario y secundario creados mediante bifurcación, los elementos de exclusión mutua robustos funcionan bien incluso con versiones anteriores de glibc. –

Cuestiones relacionadas