Werden Threads beim Aufruf von Fork kopiert?

Lesezeit: 3 Minuten

Wenn ich ein Programm mit Threads laufen und aufrufen fork() Werden die Threads auf einem Unix-basierten System kopiert? Ich weiß, dass der virtuelle Speicher für den aktuellen Prozess 1:1 in den neu erzeugten Prozess kopiert wird. Ich weiß, dass Threads ihren eigenen Stack im virtuellen Speicher eines Prozesses haben. Daher sollte zumindest der Stack von Threads mit kopiert werden. Ich weiß jedoch nicht, ob es noch mehr Threads gibt, die sich nicht im virtuellen Speicher befinden und daher NICHT kopiert werden. Wenn dies nicht der Fall ist, teilen sich die beiden Prozesse die Threads oder sind sie unabhängige Kopien?

Benutzeravatar von Jean-Baptiste Yunès
Jean-Baptiste Yunes

Nein.

Threads werden nicht kopiert fork(). POSIX-Spezifikation sagt (Hervorhebung von mir):

Fork – Erstellen Sie einen neuen Prozess

Ein Prozess soll mit einem einzigen Thread erstellt werden. Wenn ein Multithreading-Prozess fork() aufruft, soll der neue Prozess eine Kopie des aufrufenden Threads und seines gesamten Adressraums enthalten, möglicherweise einschließlich der Zustände von Mutexe und anderen Ressourcen. Folglich darf der Kindprozess zur Vermeidung von Fehlern nur asynchronsignalsichere Operationen ausführen, bis eine der exec-Funktionen aufgerufen wird.

Um dieses Problem zu umgehen, gibt es eine pthread_atfork() Funktion zu helfen.

Mann Gabel:

Der untergeordnete Prozess wird mit einem einzigen Thread erstellt – demjenigen, der fork() aufgerufen hat. Der gesamte virtuelle Adressraum des Elternteils wird im Kind repliziert, einschließlich der Zustände von Mutexes, Bedingungsvariablen und anderen pthreads-Objekten; die Verwendung von pthread_atfork(3) kann hilfreich sein, um mit Problemen umzugehen, die dies verursachen kann.

  • Aber das scheint seltsam: Warum sollte der Stapel für die Threads in dem Prozess, der die Gabelung aufruft, kopiert werden, wenn die tatsächlichen Threads (von denen ich nicht weiß, dass sie an einer anderen Stelle als dem virtuellen Speicher Speicher enthalten) nicht vorhanden sind?

    Benutzer8552461

    14. April 2020 um 12:28 Uhr

  • Also, die warum davon ist eine ganz andere Frage. Ich kenne die ursprünglichen Designentscheidungen nicht, die zu dieser Implementierung geführt haben. Wenn Sie interessiert sind, sollten Sie dies als separate Frage stellen.

    – Kaylum

    14. April 2020 um 12:29 Uhr


  • @Jean-BaptisteYunès “aber Stapel anderer Threads werden nicht kopiert” Ich glaube nicht, dass ich das gesagt habe. Ich habe mich gefragt, warum die Stapel von Threads, die sich im virtuellen Speicher befinden, in den neuen Prozess kopiert werden (da der virtuelle Speicher kopiert wird), wenn die tatsächlich ausgeführten Threads – diejenigen, die den Kontextwechsel und all das initiieren – dies nicht tun. Scheint dann wie Speicherverschwendung :/

    Benutzer8552461

    14. April 2020 um 12:51 Uhr

  • @Jean-BaptisteYunès In Unix-Systemen gibt es eine Struktur, die den virtuellen Speicher für einen Prozess darstellt. Das ist der kopierte. Nicht nur der Haufen und bss

    Benutzer8552461

    14. April 2020 um 13:45 Uhr

  • Sie erhalten den gesamten Speicherplatz – und damit die Stacks aller Threads. Sie brauchen das, weil es keine Einschränkung gibt, wohin die Zeiger im Stack (oder statischen Speicher), auf die der verbleibende Thread zugreifen kann, zeigen – sie könnten sehr gut auf Daten zeigen, die sich im ursprünglichen Prozess im Stack eines Threads befanden

    – davidbak

    15. April 2020 um 1:32 Uhr

Benutzeravatar von Ian Abbott
Ian Abbott

Aus The Open Group Base Specifications Ausgabe 7, Ausgabe 2018 Gabel:

Ein Prozess soll mit einem einzigen Thread erstellt werden. Wenn ein Multithread-Prozess aufruft Gabel()enthält der neue Prozess eine Kopie des aufrufenden Threads und seines gesamten Adressraums, möglicherweise einschließlich der Zustände von Mutexe und anderen Ressourcen. Folglich darf der Tochterprozess zur Vermeidung von Fehlern nur asynchronsignalsichere Operationen bis zu einem der folgenden Zeitpunkte ausführen Exekutive Funktionen aufgerufen werden.

Wenn die Anwendung aufruft Gabel() von einem Signal-Handler und einem der von registrierten Fork-Handler pthread_atfork() ruft eine Funktion auf, die nicht async-signalsicher ist, das Verhalten ist undefiniert.

Ursprünglich wurde “Fork” erreicht, indem die Aufgabe auf die Festplatte geschrieben und dann, anstatt einen anderen Thread einzulesen (was beim Austausch der Aufgabe mit einem anderen getan würde), die Aufgaben-ID des noch im Speicher befindlichen Bildes geändert und fortgesetzt wird mit seiner Ausführung (als neue Aufgabe). Dies war eine sehr einfache Modifikation des grundlegenden Task-Umschaltmechanismus, bei dem jeweils nur ein Task den RAM-Speicher belegte.

Als die Speicherverwaltung ausgefeilter wurde, wurde dieses Schema natürlich modifiziert, um es an die neue Umgebung anzupassen.

1388910cookie-checkWerden Threads beim Aufruf von Fork kopiert?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy