%3F.png)
Auf die obenVerknüpfungwas ist damit gemeint parent_tidptr
und child_tidptr
wodurch do_fork()
entsteht ein neuer Prozess?
Antwort1
Beginnen wir mit einem Blick auf die reine Systemaufrufschnittstelle. Sie variiert je nach Architektur etwas, aber auf x86-64 sieht sie so aus:
long clone(unsigned long flags, void *child_stack,
int *ptid, int *ctid,
unsigned long newtls);
ptid
und ctid
sind Ihre parent_tidptr
und child_tidptr
. Nun wollen wir sehen, was dieclone(2)
Die Manualpage sagt:
CLONE_CHILD_CLEARTID (since Linux 2.5.49)
Erase the child thread ID at the location ctid in
child memory when the child exits, and do a wakeup on
the futex at that address.
CLONE_CHILD_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ctid in the
child's memory.
CLONE_PARENT_SETTID (since Linux 2.5.49)
Store the child thread ID at the location ptid in the
parent's memory.
Diese Flags wurden in erster Linie für die Implementierung von Threading-Bibliotheken entwickelt. Wenn wir uns die NPTL-Implementierung vonpthread_create()
innerhalb von glibc finden wir schließlich Code insysdeps/unix/sysv/linux/createthread.c
das einen Aufruf tätigt , der und in clone()
enthält .CLONE_PARENT_SETTID
CLONE_CHILD_CLEARTID
flags
In diesem clone()
Aufruf können wir auch sehen, dass die Argumente ptid
undctid
verweisen auf die gleiche Adresse. (Denken Sie daran, dass POSIX-Threads einen Adressraum gemeinsam nutzen; dies wird mit dem clone()
CLONE_VM
Flag erreicht.)
Hier passiert also Folgendes.
CLONE_PARENT_SETTID
wird verwendet, um sicherzustellen, dass die Kernel-Thread-ID an einem bestimmten Ort im Benutzerbereich gespeichert wird. Die Benutzerbereichsseite der Thread-Implementierung muss diese Thread-ID kennen.CLONE_CHILD_CLEARTID
wird verwendet, um denselben Speicherort zu löschen (d. h. auf Null zu setzen), wenn der von erstellte Threadclone()
beendet wird.
Gehen wir noch einen Schritt weiter ...
ptid
Die über / zurückgegebene Thread-ID ctid
lautetnichtdasselbe wie eine POSIX-Thread-ID ( pthread_t
), obwohl in den 1:1-Threading-Implementierungen wie NPTL eine Eins-zu-eins-Entsprechung zwischen Kernel-Thread-IDs und POSIX-Thread-IDs besteht. Die Kernel-Thread-ID ist dieselbe ID, die Sie erhalten, wenn Sie den Linux-Thread-ID-Befehl verwenden.gettid()
clone()
call. Es wird auch als Systemaufruf-Rückgabewert zurückgegeben , was die Frage aufwirft: Warum brauchen wir ptid
/ ctid
? Das Problem ist, dass die Dinge von der Benutzerseite aus folgendermaßen aussehen:
tid = clone(...);
Aus Sicht der Threading-Implementierung im User-Space gibt es hier ein Wettrennen, da die Zuweisung tid
nur dann erfolgt ,nach clone()
zurückgibt. Das bedeutet, dass die Threading-Bibliothek im Benutzerbereich auf bestimmte Probleme stoßen kann, wenn sie diese Informationen benötigt, bevor der neue Thread etwas tut (wie zum Beispiel beendet wird). Die Verwendung CLONE_PARENT_SETTID
stellt sicher, dass die neue Thread-ID an der Stelle platziert wird, auf die von verwiesen wirdptid
Vor
clone()
gibt zurück und ermöglicht so einer Threading-Bibliothek, solche Race Conditions zu vermeiden. ( CLONE_CHILD_SETTID
kann auch mit ähnlicher Wirkung verwendet werden.)
Der Grund für CLONE_CHILD_CLEARTID
das Löschen des ptid
/ ctid
besteht darin, eine Möglichkeit für einenpthread_join()
Aufruf in einem anderen Thread, um festzustellen, dass der Thread beendet wurde. Im Wesentlichen wird der ptid
/ -Speicherort alsctid
futex, und dasfutex()
Der Systemaufruf wird zum Blockieren verwendet und wartet darauf, dass sich die Ganzzahl an dieser Stelle ändert. (Die Details sind etwas kompliziert, aber grep
für die Verwendung von lll_wait_tid
und lll_futex_wait
im Glibc-Quellcode. Letztendlich findet eine FUTEX_WAIT
Operation statt. Erinnern Sie sich an oben, das CLONE_CHILD_CLEARTID
ein Futex-Wakeup an der Zieladresse durchführt.)
Antwort2
tid
steht für „Thread-ID“. Die Parameter parent_tidptr
und child_tidptr
zeigen auf den Benutzerspeicher im Adressraum des übergeordneten bzw. des untergeordneten Prozesses. Die ID des neu erstellten Threads wird in den int-Variablen gespeichert, auf die die Zeiger zeigen.
Weitere Informationen finden Sie imclone(2)
manpage.