Ich denke, dieser Teil des clone(2)
Manpage kann den Unterschied bzgl. die PID:
CLONE_THREAD (seit Linux 2.4.0-test8)
Wenn CLONE_THREAD gesetzt ist, wird das untergeordnete Element in dieselbe Threadgruppe wie der aufrufende Prozess gestellt.
Thread-Gruppen waren eine Funktion, die in Linux 2.4 hinzugefügt wurde, um die Vorstellung von POSIX-Threads einer Gruppe von Threads zu unterstützen, die sich eine einzige PID teilen. Diese gemeinsam genutzte PID ist intern der sogenannte Threadgroup-Identifier (TGID) für die Thread-Gruppe. Seit Linux2.4 geben Aufrufe von getpid(2) die TGID des Aufrufers zurück.
Der Satz "Threads werden als Prozesse implementiert" bezieht sich auf das Problem, dass Threads in der Vergangenheit separate PIDs hatten. Grundsätzlich hatte Linux ursprünglich keine Threads innerhalb eines Prozesses, sondern nur separate Prozesse (mit separaten PIDs), die möglicherweise einige gemeinsam genutzte Ressourcen wie virtuellen Speicher oder Dateideskriptoren hatten. CLONE_THREAD
und die Trennung von Prozess-ID und Thread-ID lassen das Linux-Verhalten eher wie andere Systeme und in diesem Sinne eher wie die POSIX-Anforderungen aussehen. Obwohl das Betriebssystem technisch gesehen immer noch keine separaten Implementierungen für Threads und Prozesse hat.
Die Signalverarbeitung war ein weiterer problematischer Bereich bei der alten Implementierung. Dies wird ausführlicher in dem Papier beschrieben, auf das @FooF in seiner Antwort verweist.
Wie in den Kommentaren erwähnt, wurde Linux 2.4 ebenfalls im Jahr 2001 veröffentlicht, im selben Jahr wie das Buch, daher ist es nicht verwunderlich, dass die Neuigkeiten nicht bis zu dieser Auflage gelangten.
Sie haben Recht, in der Tat „muss sich zwischen 2001 und heute etwas geändert haben“. Das Buch, das Sie gerade lesen, beschreibt die Welt gemäß der ersten historischen Implementierung von POSIX-Threads auf Linux, genannt LinuxThreads (siehe auch Wikipedia-Artikel für einige).
LinuxThreads hatte einige Kompatibilitätsprobleme mit dem POSIX-Standard - zum Beispiel Threads, die keine PIDs teilen - und einige andere ernsthafte Probleme. Um diese Fehler zu beheben, wurde eine weitere Implementierung namens NPTL (Native POSIX Thread Library) von Red Hat angeführt, um die notwendige Kernel- und Userspace-Bibliotheksunterstützung hinzuzufügen, um eine bessere POSIX-Konformität zu erreichen (wobei gute Teile eines weiteren konkurrierenden Neuimplementierungsprojekts von IBM namens NGPT (" Posix-Threads der nächsten Generation"), siehe Wikipedia-Artikel zu NPTL). Die zusätzlichen Flags, die zu clone(2)
hinzugefügt wurden Systemaufruf (insbesondere CLONE_THREAD
dass @ikkkachu
weist in seiner Antwort darauf hin) ist wahrscheinlich der offensichtlichste Teil der Kernel-Modifikationen. Der User-Space-Teil der Arbeit wurde schließlich in die GNU C Library integriert.
Heutzutage verwenden immer noch einige eingebettete Linux-SDKs die alte LinuxThreads-Implementierung, weil sie eine Version von LibC mit kleinerem Speicherbedarf namens uClibc (auch µClibc genannt) verwenden, und es dauerte viele Jahre, bis die NPTL-Benutzerraumimplementierung von GNU LibC portiert wurde und als standardmäßige POSIX-Threading-Implementierung angenommen, da diese speziellen Plattformen im Allgemeinen nicht danach streben, blitzschnell den neuesten Moden zu folgen. Die Verwendung der LinuxThreads-Implementierung im Betrieb kann beobachtet werden, indem man feststellt, dass die PIDs für verschiedene Threads auf diesen Plattformen anders sind als der POSIX-Standard spezifiziert - genau wie das Buch, das Sie gerade lesen, beschreibt. Eigentlich einmal, als Sie pthread_create()
angerufen haben , Sie hatten die Anzahl der Prozesse plötzlich von eins auf drei erhöht, da zusätzliche Prozesse erforderlich waren, um das Durcheinander zusammenzuhalten.
Die Handbuchseite Linux pthreads(7) bietet einen umfassenden und interessanten Überblick über die Unterschiede zwischen den beiden. Eine weitere aufschlussreiche, wenn auch veraltete Beschreibung der Unterschiede ist dieser Artikel von Ulrich Depper und Ingo Molnar über das Design von NPTL.
Ich empfehle Ihnen, diesen Teil des Buches nicht zu ernst zu nehmen. Ich empfehle stattdessen Butenhofs Programmieren von POSIX-Threads und POSIX- und Linux-Handbuchseiten zu diesem Thema. Viele Tutorials zu diesem Thema sind ungenau.
(Userspace)-Threads werden unter Linux nicht als Prozesse implementiert, da sie keinen eigenen privaten Adressraum haben, sondern sich den Adressraum des übergeordneten Prozesses teilen.
Diese Threads sind jedoch so implementiert, dass sie das Prozessabrechnungssystem des Kernels verwenden, ihnen wird also ihre eigene Thread-ID (TID) zugewiesen, sie erhalten jedoch dieselbe PID und 'Thread-Gruppen-ID' (TGID) wie der übergeordnete Prozess - dies im Gegensatz zu ein Fork, bei dem eine neue TGID und PID erstellt werden und die TID dieselbe ist wie die PID.
Es scheint also, dass neuere Kernel eine separate TID hatten, die abgefragt werden kann, das ist das, was für Threads anders ist, ein geeigneter Codeausschnitt, um dies in jedem der main() thread_function() oben zu zeigen, ist:
long tid = syscall(SYS_gettid);
printf("%ld\n", tid);
Der gesamte Code mit diesem wäre also:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <syscall.h>
void* thread_function (void* arg)
{
long tid = syscall(SYS_gettid);
printf("child thread TID is %ld\n", tid);
fprintf (stderr, "child thread pid is %d\n", (int) getpid ());
/* Spin forever. */
while (1);
return NULL;
}
int main ()
{
pthread_t thread;
long tid = syscall(SYS_gettid);
printf("main TID is %ld\n", tid);
fprintf (stderr, "main thread pid is %d\n", (int) getpid ());
pthread_create (&thread, NULL, &thread_function, NULL);
/* Spin forever. */
while (1);
return 0;
}
Geben Sie eine Beispielausgabe von:
main TID is 17963
main thread pid is 17963
thread TID is 17964
child thread pid is 17963