2009-11-09 4 views
14

Supposons qu'un processus crée un mutex dans la mémoire partagée et qu'il le verrouille et qu'il vide le cœur pendant que le mutex est verrouillé.Mutex en mémoire partagée lorsqu'un utilisateur tombe en panne?

Maintenant, dans un autre processus, comment puis-je détecter que le mutex est déjà verrouillé mais qu'il n'appartient à aucun processus?

Répondre

8

Si vous travaillez sous Linux ou quelque chose de similaire, pensez à utiliser named semaphores au lieu de (ce que je suppose sont) pthreads mutex. Je ne pense pas qu'il existe un moyen de déterminer le PID de verrouillage d'un mutex pthreads, à moins de construire votre propre table d'enregistrement et de le mettre en mémoire partagée.

+4

D'accord en général avec la recommandation de sémaphore, mais les sémaphores POSIX ne résolvent pas vraiment le problème puisqu'ils n'enregistrent pas non plus le PID du processus de verrouillage ni ne se débloquent en cas de décès prématuré. Rusty et maladroit, bien qu'ils puissent être des sémaphores SysV, ils gardent une trace des PID et peuvent revenir en arrière lorsqu'ils sont appelés avec l'option SEM_UNDO. – Duck

1

Vous devez utiliser un sémaphore fourni par le système d'exploitation.

Le système d'exploitation libère toutes les ressources ouvertes par un processus, qu'il soit actif ou non.

+0

Pas dans toutes les ressources. Si OP utilise le sémaphore POSIX comme suggéré et que le processus contenant le verrou meurt, la valeur du sémaphore ne reviendra pas, ce qui pourrait bloquer les autres processus. – Duck

1

J'ai laissé ce mauvais message supprimé seulement si quelqu'un aura la même idée et trouvera cette discussion d'utilisation!


Vous pouvez utiliser cette approche. 1) Verrouiller le mutex partagé POSIX 2) Enregistrer l'ID de processus dans la mémoire partagée. 3) Débloquer le mutex partagé 4) A la sortie correcte nettoyer le processus id

Si le processus coredumps le processus suivant se trouve que dans la mémoire partagée il y a un processus id enregistré sur l'étape 2. S'il n'y a pas de processus avec cet ID de processus dans le système d'exploitation, personne ne possède le mutex partagé. Il est donc juste nécessaire de remplacer le processus-ID.

mise à jour afin de répondre à ce commentaire:

Scénario 1: 1. P1 commence 2. P1 crée/ouvre un mutex nommé si elle n'existe pas 3. P1 timed_locks le mutex nommé et succčs le fait (attend 10 secondes si nécessaire); 4. P1 coredumps 5. P2 commence après le coredump 6. P2 crée/ouvre un mutex nommé, il existe, c'est OK 7. P2 timed_locks le mutex nommé et ne parvient pas à se verrouiller (attend 10 secondes si nécessaire); 8. P2 retirer le mutex nommé 9. P2 reconstitue un mutex nommé & enclenchez

+0

Je ne vois pas de solution ici. Scénario 1: (1) verrous P1; (2) matrices P1; (3) impasse. Scénario 2: (1) verrous P1; (2) P1 écrit pid; (3) P1 déverrouille; (4) P2 obtient le contrôle et verrouille et trouve P1 pid. Scénario 3: Si la commande est commutée de sorte que le pid est effacé avant le déverrouillage et le processus meurt, vous êtes de retour au problème original que le processus mort maintient le verrou et bloque les autres processus. Est-ce que je manque quelque chose? – Duck

+0

Scénario commenté n ° 1 –

+0

La mise à jour est irréalisable. La dépendance à un moment arbitraire est mauvaise. Mais pire, si plus d'un processus essaie d'exécuter cette formule, tout l'enfer peut se déchaîner pendant le temps de suppression, de recréation, de verrouillage, etc., du mutex. – Duck

5

Que diriez-vous du verrouillage par fichier (using flock(2))? Ceux-ci sont automatiquement libérés lorsque le processus qui le contient meurt.

programme de démonstration:

#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; 
} 

sortie (je l'ai tronqué les PIDs et parfois un peu de clarté):

$ ./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 

Ce qui se passe est que le premier programme acquiert le verrou et commence à dors pendant 5 secondes. Au bout de 2 secondes, une seconde instance du programme est démarrée et bloque en essayant d'acquérir le verrou. 3 secondes plus tard, le premier programme segfaults (bash ne vous dit pas cela plus tard cependant) et immédiatement, le deuxième programme obtient le verrou et continue.

+0

Je ne pense pas que taht sera supprimé aussi bien que ce soit le fichier ou la mémoire c'est la même chose pour les deux. – Vivek

+0

Je ne veux pas dire en écrivant quelque chose à l'intérieur du fichier (qui serait en effet similaire), mais en utilisant 'flock (2)'. Quand votre processus meurt, le fichier sera automatiquement fermé, et le verrou dessus devrait être libéré. – Wim

+0

+1 seul flock (fileno (f), LOCK_EX | LOCK_NB) est plus sûr – dashesy

30

Il semble que la réponse exacte ait été fournie sous la forme de mutex robustes.

Selon POSIX, les mutex pthread peuvent être initialisés "robustes" en utilisant pthread_mutexattr_setrobust(). Si un processus contenant le mutex meurt alors, le thread suivant pour l'acquérir recevra EOWNERDEAD (mais obtiendra toujours le mutex avec succès) afin qu'il sache effectuer un nettoyage. Il doit ensuite notifier que le mutex acquis est à nouveau cohérent en utilisant pthread_mutex_consistent().

De toute évidence, vous avez besoin du support du noyau et de la libc pour que cela fonctionne. Sous Linux, le support du noyau est appelé "robustes futex", et j'ai trouvé des références aux mises à jour de l'espace utilisateur appliquées à la glibc HEAD.

En pratique, le support pour cela ne semble pas encore avoir filtré, du moins dans le monde Linux. Si ces fonctions ne sont pas disponibles, vous pouvez trouver pthread_mutexattr_setrobust_np() à la place, ce qui, pour autant que je puisse en déduire, semble être un prédécesseur non-POSIX fournissant la même sémantique. J'ai trouvé des références à pthread_mutexattr_setrobust_np() à la fois dans la documentation Solaris et dans /usr/include/pthread.h sur Debian.

La spécification Posix se trouve ici: http://www.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setrobust.html

+3

Je pense que c'est une meilleure réponse. J'ai utilisé le mutex robuste sur Solaris jusqu'à présent avec succès. –

+2

Les mutex robustes sont géniaux, mais sachez qu'ils peuvent ne pas fonctionner correctement sous GNU/Linux avant glibc 2.15 si le mutex a été créé dans un processus parent qui se transforme alors en forks et que l'enfant meurt en maintenant le mutex. Ce [bug] (http://sourceware.org/bugzilla/show_bug.cgi?id=13002) est corrigé dans la glibc 2.15. Si les deux processus partageant le mutex ne sont pas un parent et un enfant créés en forçant, alors les mutex robustes fonctionnent bien même avec les anciennes versions de la glibc. –

Questions connexes