Ist es möglich, den Thread zu bestimmen, der einen Mutex enthält?

70

Erstens benutze ich die pthread-Bibliothek, um ein Multithreading-C-Programm zu schreiben. Fäden hingen immer an ihren warteten Mutexen. Wenn ich das Dienstprogramm strace verwende, um festzustellen, ob sich ein Thread im FUTEX_WAITStatus befindet, möchte ich wissen, welcher Thread diesen Mutex zu diesem Zeitpunkt enthält. Aber ich weiß nicht, wie ich es schaffen könnte. Gibt es Dienstprogramme, die das tun könnten?

Jemand hat mir gesagt, dass Java Virtual Machine dies unterstützt, daher möchte ich wissen, ob Linux diese Funktion unterstützt.

Frottee
quelle

Antworten:

119

Hierzu können Sie Kenntnisse der Mutex-Interna verwenden. Normalerweise wäre dies keine sehr gute Idee, aber es ist in Ordnung zum Debuggen.

Unter Linux mit der NPTL-Implementierung von pthreads (was jedes moderne glibc ist) können Sie das __data.__ownerMitglied der pthread_mutex_tStruktur untersuchen, um herauszufinden, in welchem Thread es derzeit gesperrt ist. So geht's nach dem Anhängen an den Prozess mit gdb:

(Ich wechsle zum hängenden Thread; mache eine Rückverfolgung, um den zu finden pthread_mutex_lock() wechsle zum hängengebliebenen festzustellen, ob er festsitzt. Ändern Sie die Stapelrahmen, um den Namen des Mutex herauszufinden, den Sie sperren möchten. Drucken Sie dann den Besitzer dieses Mutex aus.) Dies sagt mir, dass der Thread mit der LWP ID 22025 der Schuldige ist.

Sie können dann thread find 22025die gdbThread-Nummer für diesen Thread ermitteln und zu dieser wechseln.

caf
quelle
1
Gibt es eine Möglichkeit, Daten .__ owner__ mit der pthread-Thread-ID zu korrelieren ? Beim Spielen habe ich einfach log << mutex .__ data __. Owner << endl codiert und das scheint gut zu funktionieren. Aber der data.owner ist ein Wert wie 9841, während der tid wie 140505876686608 ist. Wie ist die Beziehung zwischen den beiden Werten?
Ente
5
@ Ente: Der Wert in .__data.__ownerist eine TID. Wenn jeder Thread startet, können sie einfach ihre TID (using tid = syscall(SYS_gettid);) sowie ihre pthread_t(from pthread_self()) protokollieren lassen .
Café
1
Sie können auch den Stapelzeiger des Threads in der statDatei in untersuchen proc, und er liegt ziemlich nahe (innerhalb weniger KB) am pthread_tWert. :-)
R .. GitHub STOP HELPING ICE
2
Übrigens: Man könnte info threadsTIDs ( .__data.__owner) pthread-IDs zuordnen (die IDs, mit denen man in gdb arbeitet).
Adam Romanek
8
@caf, du kannst deiner Antwort hinzufügen, dass es heutzutage in gdb einen thread findBefehl gibt. So , nachdem das Auffinden mutex.__data.__owner22025 ist , können Sie laufen: thread find 22025und die Nummer des Themas in GDB erhalten: (Beispiel: Thread 29 has target id 'Thread 0x7fffdf5fe700 (LWP 22025)' ). So können Sie als nächstes mit dem Befehl zu dem Thread wechseln, der die Sperre hält: thread 29oder einfacht 29
5

Ich kenne keine solche Einrichtung, daher denke ich nicht, dass Sie so leicht davonkommen werden - und es wäre wahrscheinlich nicht so informativ, wie Sie denken, wenn Sie beim Debuggen Ihres Programms helfen. So Low-Tech es auch scheinen mag, die Protokollierung ist Ihr Freund beim Debuggen dieser Dinge. Sammeln Sie Ihre eigenen kleinen Protokollierungsfunktionen. Sie müssen nicht ausgefallen sein, sie müssen nur die Arbeit beim Debuggen erledigen.

Entschuldigung für das C ++, aber so etwas wie:

Die Protokollierung ist keine perfekte Lösung, aber nichts. Normalerweise erhalten Sie das, was Sie wissen müssen.

Ente
quelle
Die Protokollierung ist in der Tat ein sehr nützliches Tool zum Debuggen. Vielen Dank für Ihre Vorschläge.
Terry
1
+1 Wer liebt es nicht zu protokollieren? Mit LD_PRELOAD (und etwas Geduld) konnte dies ohne Codeänderungen durchgeführt werden. Wrap- pthread_mutex_*Funktionen mit etwas, das die Funktionsaufrufe, die Mutex-Adresse und eine Thread-ID protokolliert ( pthread_tzufällig ein integraler Typ unter Linux, keine tragbare Annahme, aber eine ziemliche Bequemlichkeit).
Pilcrow
7
Ein mögliches Problem bei der Protokollierung besteht darin, dass das Timing gestört und das Problem behoben werden kann.
Spudd86
Außerdem können Sie Bibliotheksfunktionen nicht immer / vorhersehbar einfügen. Es ist keine Garantie.
Matt Joiner
Die Protokollierung ist sehr nützlich. Es gibt jedoch einige Stellen, an denen die Protokollierung nicht sicher ist. Insbesondere mallocist es an bestimmten Stellen nicht sicher - zum Beispiel in Signalhandlern, Atfork-Handlern, zwischen Fork und Exec in einem Multithread-Programm usw. Siehe Async-Signal-Sicherheit und die anderen Manpages.
mgarey
2

Normalerweise werden libc / platform-Aufrufe von der OS-Abstraktionsschicht abstrahiert. Die toten Mutex-Sperren können mithilfe einer Eigentümervariablen und pthread_mutex_timedlock verfolgt werden. Immer wenn der Thread gesperrt wird, sollte er die Variable mit der eigenen tid (gettid () aktualisieren und kann auch eine andere Variable für die Speicherung der pthread-ID haben). Wenn also die anderen Threads blockieren und das Zeitlimit für pthread_mutex_timedlock überschritten wird, kann der Wert von Eigentümer tid und pthread_id gedruckt werden. Auf diese Weise können Sie den Eigentümer-Thread leicht herausfinden. Bitte finden Sie das Code-Snippet unten. Beachten Sie, dass nicht alle Fehlerbedingungen behandelt werden

Es gibt andere Möglichkeiten, um tote Sperren herauszufinden. Vielleicht hilft dieser Link http://yusufonlinux.blogspot.in/2010/11/debugging-core-using-gdb.html .

Yusuf Khan
quelle