In errno.h
wird diese Variable so deklariert, extern int errno;
dass meine Frage lautet: errno
Ist es sicher, den Wert nach einigen Aufrufen zu überprüfen oder perror () in Multithread-Code zu verwenden? Ist das eine thread-sichere Variable? Wenn nicht, was ist dann die Alternative?
Ich verwende Linux mit gcc auf x86-Architektur.
c
linux
multithreading
gcc
vinit dhatrak
quelle
quelle
Antworten:
Ja, es ist threadsicher. Unter Linux ist die globale Variable errno threadspezifisch. POSIX erfordert, dass errno threadsicher ist.
Siehe http://www.unix.org/whitepapers/reentrant.html
Siehe auch http://linux.die.net/man/3/errno
quelle
# if !defined _LIBC || defined _LIBC_REENTRANT
beim Kompilieren normaler Programme nicht definiert sein. Wie auch immer, führen Sie echo aus#include <errno.h>' | gcc -E -dM -xc -
und sehen Sie sich den Unterschied mit und ohne -pthread an. errno ist#define errno (*__errno_location ())
in beiden Fällen.Ja
Errno ist keine einfache Variable mehr, es ist etwas Komplexes hinter den Kulissen, speziell damit es threadsicher ist.
Siehe
$ man 3 errno
:Wir können überprüfen:
quelle
Folgendes sagt der C-Standard:
Im Allgemeinen
errno
handelt es sich um ein Makro, das eine Funktion aufruft, die die Adresse der Fehlernummer für den aktuellen Thread zurückgibt und diese dann dereferenziert.Folgendes habe ich unter Linux in /usr/include/bits/errno.h:
Am Ende generiert es diese Art von Code:
quelle
Auf vielen Unix-Systemen stellt das Kompilieren mit
-D_REENTRANT
sicher, dasserrno
es threadsicher ist.Beispielsweise:
quelle
-D_REENTRANT
. Bitte beziehen Sie sich auf die Diskussion über andere Antworten für dieselbe Frage.-D_XOPEN_SOURCE=500
oder-D_XOPEN_SOURCE=600
. Nicht jeder kümmert sich darum, dass die POSIX-Umgebung angegeben wird - und-D_REENTRANT
kann dann Ihren Speck retten. Sie müssen jedoch auf jeder Plattform vorsichtig sein, um sicherzustellen, dass Sie das gewünschte Verhalten erhalten.errno
erweitert sich zu einem modifizierbaren Wert (201) mitint
lokaler Speicherdauer für Typ und Thread, dessen Wert von mehreren Bibliotheksfunktionen auf eine positive Fehlernummer gesetzt wird. Wenn eine Makrodefinition unterdrückt wird, um auf ein tatsächliches Objekt zuzugreifen, oder ein Programm einen Bezeichner mit dem Namen definierterrno
, ist das Verhalten undefiniert. [... Fortsetzung ...]errno
muss nicht die Kennung eines Objekts sein. Es kann sich zu einem veränderbaren Wert erweitern, der sich aus einem Funktionsaufruf ergibt (z. B.*errno()
). Der Haupttext wird fortgesetzt: Der Wert von errno im Anfangsthread ist beim Programmstart Null (der Anfangswert von errno in anderen Threads ist ein unbestimmter Wert), wird jedoch von keiner Bibliotheksfunktion auf Null gesetzt. POSIX verwendet den C99-Standard, der keine Threads erkannte. [... auch weiter ...]Dies ist von
<sys/errno.h>
auf meinem Mac:So
errno
ist jetzt eine Funktion__error()
. Die Funktion ist threadsicher implementiert.quelle
Ja , wie in der Manpage errno und den anderen Antworten erläutert, ist errno eine lokale Thread-Variable.
Es gibt jedoch ein dummes Detail, das leicht vergessen werden könnte. Programme sollten die Fehlernummer auf jedem Signalhandler speichern und wiederherstellen, der einen Systemaufruf ausführt. Dies liegt daran, dass das Signal von einem der Prozessthreads verarbeitet wird, der seinen Wert überschreiben könnte.
Daher sollten die Signalhandler errno speichern und wiederherstellen. Etwas wie:
quelle
Ich denke die Antwort ist "es kommt darauf an". Thread-sichere C-Laufzeitbibliotheken implementieren normalerweise errno als Funktionsaufruf (Makro wird zu einer Funktion erweitert), wenn Sie Thread-Code mit den richtigen Flags erstellen.
quelle
Wir können dies überprüfen, indem wir ein einfaches Programm auf einer Maschine ausführen.
Wenn Sie dieses Programm ausführen, werden in jedem Thread unterschiedliche Adressen für errno angezeigt. Die Ausgabe eines Laufs auf meinem Computer sah folgendermaßen aus:
Beachten Sie, dass die Adresse für alle Threads unterschiedlich ist.
quelle