GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Ist es sicher, innerhalb eines Threads zu forken?

Das Problem ist, dass fork() nur den aufrufenden Thread kopiert und alle in untergeordneten Threads enthaltenen Mutexe für immer im gegabelten untergeordneten Thread gesperrt sind. Die pthread-Lösung war pthread_atfork() Handler. Die Idee war, dass Sie 3 Handler registrieren können:einen Prefork, einen Eltern-Handler und einen Kind-Handler. Wenn fork() passiert prefork wird vor fork aufgerufen und soll alle Anwendungs-Mutexe abrufen. Sowohl Parent als auch Child müssen alle Mutexe in Parent- bzw. Child-Prozessen freigeben.

Dies ist jedoch nicht das Ende der Geschichte! Bibliotheken nennen pthread_atfork Um Handler für bibliotheksspezifische Mutexe zu registrieren, tut dies beispielsweise Libc. Das ist eine gute Sache:Die Anwendung kann unmöglich von den Mutexes wissen, die von Bibliotheken von Drittanbietern gehalten werden, also muss jede Bibliothek pthread_atfork aufrufen um sicherzustellen, dass seine eigenen Mutexe im Falle eines fork() bereinigt werden .

Das Problem ist, dass die Bestellung pthread_atfork Handler für nicht verwandte Bibliotheken aufgerufen werden, ist undefiniert (es hängt von der Reihenfolge ab, in der die Bibliotheken vom Programm geladen werden). Das bedeutet also, dass es technisch gesehen aufgrund einer Rennbedingung zu einem Deadlock innerhalb eines Prefork-Handlers kommen kann.

Betrachten Sie beispielsweise diese Sequenz:

  1. Thread T1 ruft fork() auf
  2. libc-Prefork-Handler werden in T1 aufgerufen (z. B. hält T1 jetzt alle libc-Sperren)
  3. Als nächstes erwirbt in Thread T2 eine Bibliothek A eines Drittanbieters ihren eigenen Mutex AM und führt dann einen libc-Aufruf durch, der einen Mutex erfordert. Dies blockiert, weil libc Mutexe von T1 gehalten werden.
  4. Thread T1 führt den Prefork-Handler für Bibliothek A aus, der das Warten auf den Erhalt von AM blockiert, das von T2 gehalten wird.

Es gibt Ihren Deadlock, der nichts mit Ihren eigenen Mutexes oder Code zu tun hat.

Das ist tatsächlich bei einem Projekt passiert, an dem ich einmal gearbeitet habe. Der Rat, den ich damals gefunden hatte, war, Gabel oder Gewinde zu wählen, aber nicht beides. Aber für einige Anwendungen ist das wahrscheinlich nicht praktikabel.


Es ist sicher, ein Multithread-Programm zu verzweigen, solange Sie sehr sind Achten Sie auf den Code zwischen Fork und Exec. Sie können in dieser Spanne nur wiedereintrittsfähige (auch als asynchron sichere) Systemaufrufe tätigen. Theoretisch dürfen Sie dort nicht mallocieren oder freigeben, obwohl in der Praxis der Standard-Linux-Allokator sicher ist und Linux-Bibliotheken sich darauf verlassen. Das Endergebnis ist, dass Sie müssen Verwenden Sie die Standardzuweisung.


Linux
  1. Programm aus einem C-Programm heraus ausführen

  2. Wie extrahiere ich einen einzelnen Byteblock aus einer Datei?

  3. Thread-ID vs. Thread-Handle

  4. Bash:Ausführen von Befehlen innerhalb einer Chroot und Wechseln des Benutzers

  5. Ändern Sie die Qt-GUI aus dem Hintergrund-Worker-Thread

Wie man von Vim aus auf die Shell zugreift oder externe Befehle ausführt

Schützen Sie CentOS 6-Server vor einer neuen OpenSSL-Schwachstelle

Vollständigen Pfad aus Bash-Skript abrufen?

Upgrade von Ubuntu in Docker von 14.04 auf 16.04 mit Do-release-upgrade?

So verwenden Sie Webmail innerhalb von cPanel

Erstellen Sie symbolische NTFS-Links innerhalb von Linux