2009-11-09 11 views
14

Angenommen, ein Prozess erstellt einen Mutex im gemeinsam genutzten Speicher, sperrt ihn und löscht den Core, während der Mutex gesperrt ist.Mutex im Shared Memory wenn ein Benutzer abstürzt?

Jetzt in einem anderen Prozess, wie kann ich erkennen, dass Mutex bereits gesperrt ist, aber nicht von einem Prozess gehört?

Antwort

8

Wenn Sie arbeiten in Linux oder etwas ähnliches, sollten Sie mit named semaphores statt mutexes (was ich annehme) sind pThreads nachbildet. Ich glaube nicht, dass es eine Möglichkeit gibt, die Sperr-PID eines Pthreads-Mutex zu bestimmen, kurz davor, eine eigene Registrierungstabelle zu erstellen und diese in den gemeinsamen Speicher zu legen.

+4

Stimmen Sie im Allgemeinen mit der Semaphor-Empfehlung überein, aber POSIX-Semaphoren lösen das Problem nicht wirklich, da sie auch nicht die PID des Sperrprozesses aufzeichnen oder bei vorzeitigem Tod entsperren. Rostig und ungeschickt, obwohl sie SysV-Semaphore sein können, behalten sie die PIDs im Auge und können sie wiederherstellen, wenn sie mit der Option SEM_UNDO aufgerufen werden. – Duck

1

Sie sollten ein Semaphor verwenden, wie es vom Betriebssystem bereitgestellt wird.

Das Betriebssystem gibt alle Ressourcen frei, die ein Prozess geöffnet hat, unabhängig davon, ob er abstirbt oder ordnungsgemäß beendet wird.

+0

Nicht in allen Ressourcen. Wenn OP den POSIX-Semaphor wie vorgeschlagen verwendet und der Prozess, der die Sperre hält, stirbt, wird der Wert des Semaphors nicht zurückgesetzt, wodurch möglicherweise die anderen Prozesse blockiert werden. – Duck

1

Ich habe diese FALSCHE Post gelöscht, nur wenn jemand die gleiche Idee haben wird und diese Diskussion der Verwendung finden wird!


Sie können diesen Ansatz verwenden. 1) Sperren Sie den gemeinsamen POSIX-Mutex 2) Speichern Sie die Prozess-ID im Shared Memory. 3) Schalte den freigegebenen Mutex 4) Am richtigen Ausgang reinigen die Prozess-ID

Wenn der Prozess der nächste Prozess coredumps, dass in dem gemeinsam genutzten Speicher finden gibt es einen Prozess-ID auf Schritt # 2 gespeichert. Wenn es im Betriebssystem keinen Prozess mit dieser Prozess-ID gibt, besitzt niemand den geteilten Mutex. Es ist also nur notwendig, die Prozess-ID zu ersetzen.

aktualisieren, um den Kommentar zu beantworten:

Szenario 1: 1. P1 startet 2. P1 erzeugt/öffnet einen benannten Mutex, wenn es nicht vorhanden ist 3. P1 timed_locks den benannten Mutex und successfuly tut es (wartet 10 Sekunden wenn nötig); 4. P1 Coredumps 5. P2 startet nach dem Coredump 6. P2 erstellt/öffnet einen benannten Mutex, es existiert, es ist in Ordnung 7. P2 timed_locks den benannten Mutex und kann nicht sperren (wartet für 10 Sekunden wenn nötig); 8. P2 entfernen Sie den benannten Mutex 9. P2 einen benannten Mutex & arretieren

+0

Ich sehe hier keine Lösung. Szenario 1: (1) P1-Sperren; (2) P1 stirbt ab; (3) Deadlock. Szenario 2: (1) P1-Sperren; (2) P1 schreibt pid; (3) P1 entriegelt; (4) P2 erhält die Kontrolle und sperrt und findet P1 pid. Szenario 3: Wenn die Reihenfolge geändert wird, so dass die PID vor dem Entsperren gelöscht wird und der Prozess abbricht, sind Sie wieder beim ursprünglichen Problem, dass der tote Prozess die Sperre hält und die anderen Prozesse blockiert. Fehle ich etwas? – Duck

+0

Kommentiertes Szenario # 1 –

+0

Das Update ist nicht durchführbar. Die Abhängigkeit von einer beliebigen Zeit ist schlecht. Aber schlimmer, wenn mehr als ein Prozess versucht, diese Formel auszuführen, kann die Hölle während der Zeit des Löschens, Neuerzeugens, Verriegelns usw. des Mutex losbrechen. – Duck

5

Wie wäre es mit dateibasierten Sperren (mit flock(2))? Diese werden automatisch freigegeben, wenn der Prozess, der sie hält, stirbt.

Demo-Programm:

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

Ausgang (Ich habe die PIDs und mal etwas für Klarheit gekürzt):

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

Was passiert, ist, dass das erste Programm die Sperre erfasst und beginnt zu Schlaf für 5 Sekunden. Nach 2 Sekunden wird eine zweite Instanz des Programms gestartet, die blockiert, während versucht wird, die Sperre zu erhalten. 3 Sekunden später, das erste Programm segfaults (bash sagt Ihnen das nicht bis später) und sofort, das zweite Programm bekommt die Sperre und geht weiter.

+0

Ich denke nicht, dass das auch entfernt werden wird, da es entweder Datei oder Speicher ist, die gleiche Sache für beide. – Vivek

+0

Ich meine nicht, indem ich etwas in die Datei schreibe (was in der Tat ähnlich wäre), sondern 'flock (2)' zu verwenden. Wenn Ihr Prozess stirbt, wird die Datei automatisch geschlossen und die Sperre sollte aufgehoben werden. – Wim

+0

+1 nur diese Herde (fileno (f), LOCK_EX | LOCK_NB) ist sicherer – dashesy

30

Es scheint, dass die genaue Antwort in Form von robusten Mutexe bereitgestellt wurde.

Laut POSIX können Pthread-Mutexe mit pthread_mutexattr_setrobust() "robust" initialisiert werden. Wenn ein Prozess, der den Mutex hält, dann stirbt, erhält der nächste Thread, der ihn erhält, EOWNERDEAD (aber erwirbt immer noch den Mutex erfolgreich), so dass er weiß, dass er eine Bereinigung durchführen muss. Er muss dann mit pthread_mutex_consistent() darüber informieren, dass der erworbene Mutex wieder konsistent ist.

Offensichtlich benötigen Sie sowohl Kernel-und libc-Unterstützung, damit dies funktioniert. Unter Linux heißt die Kernel-Unterstützung "robust futexes", und ich habe Referenzen zu Userspace-Updates gefunden, die auf glibc HEAD angewendet werden.

In der Praxis scheint die Unterstützung dafür zumindest in der Linux-Welt noch nicht gefiltert zu sein. Wenn diese Funktionen nicht verfügbar sind, können Sie statt dessen pthread_mutexattr_setrobust_np() finden, was meines Wissens nach ein Nicht-POSIX-Vorgänger ist, der die gleiche Semantik bietet. Ich habe Referenzen zu pthread_mutexattr_setrobust_np() sowohl in der Solaris-Dokumentation als auch in /usr/include/pthread.h auf Debian gefunden.

Die POSIX-Spezifikation finden Sie hier: http://www.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setrobust.html

+3

Ich denke, das ist eine bessere Antwort. Ich habe den robusten Mutex auf Solaris bisher erfolgreich eingesetzt. –

+2

Robuste Mutexe sind großartig, aber beachte, dass sie vor GNU/Linux vor Glibc 2.15 möglicherweise nicht korrekt funktionieren, wenn der Mutex in einem Elternprozess erstellt wurde, der dann fork und das Kind stirbt, während er den Mutex hält. Dieser [Bug] (http://sourceware.org/bugzilla/show_bug.cgi?id=13002) wurde in glibc 2.15 behoben. Wenn die beiden Prozesse, die sich den Mutex teilen, keine übergekoppelten Eltern und Kinder sind, dann funktionieren robuste Mutexe auch mit älteren glibc-Versionen. –