Ist Malloc fadensicher?

74

Ist die malloc()Funktion wieder verfügbar?

Alphaneo
quelle
42
Ihr Titel und Ihr Körper fragen zwei verschiedene Dinge. Wiedereintritt bedeutet normalerweise "kann sicher in einem Signalhandler verwendet werden", während threadsicher normalerweise bedeutet "kann sicher in Threads verwendet werden". Es ist einfacher, threadsicher zu sein als wieder einzutreten.
David Thornley

Antworten:

47

Ich habe irgendwo gelesen, dass malloc threadsicher wird, wenn Sie mit -pthread kompilieren. Ich bin mir ziemlich sicher, dass die Implementierung davon abhängt, da malloc ANSI C ist und Threads nicht.

Wenn wir über gcc sprechen:

Das Kompilieren und Verknüpfen mit -pthread und malloc () ist auf x86 und AMD64 threadsicher.

http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2431a99b9bdcef11/ea800579e40f7fa4

Eine andere Meinung, aufschlussreicher

{malloc, calloc, realloc, free, posix_memalign} von glibc-2.2 + sind threadsicher

http://linux.derkeiler.com/Newsgroups/comp.os.linux.development.apps/2005-07/0323.html

Tom
quelle
15
"Ich lese irgendwo ..." ist wirklich nicht die Qualität, die zu einer akzeptierten Antwort
passt
12
Was auch immer er die Referenzlinks zur Verfügung stellt.
Kette ro
3
Beachten Sie, dass das einfache Hinzufügen -pthreadsden Malloc-Thread nicht automatisch sicher macht. Wenn Sie malloc in einem Signalhandler aufrufen, können alle Arten von verrücktem Unsinn passieren.
DIMMSum
2
Es ist nicht sicher, dass malloc von einem Signalhandler angerufen wird. sehr wenig ist. Es kann in einigen Kontexten funktionieren, aber nicht legal oder portabel AFAIK (siehe en.cppreference.com/w/c/program/signal , man7.org/linux/man-pages/man7/signal-safety.7.html )
Oliver Seiler
102

Frage: "Ist Malloc wiedereintrittsfähig?"
Antwort: Nein, das ist es nicht. Hier ist eine Definition dessen, was einen routinemäßigen Wiedereintritt ausmacht .

In keiner der gängigen Versionen von malloc können Sie es erneut eingeben (z. B. von einem Signalhandler). Beachten Sie, dass eine Wiedereintrittsroutine möglicherweise keine Sperren verwendet und fast alle existierenden Malloc-Versionen Sperren (wodurch sie threadsicher sind) oder globale / statische Variablen (wodurch sie threadsicher und nicht wiedereintrittsfähig sind) verwenden.

Alle bisherigen Antworten antworten auf "Ist Malloc-Thread-sicher?", Was eine ganz andere Frage ist. Um diese Frage , die Antwort ist es hängt auf Ihrer Laufzeitbibliothek und möglicherweise auf dem Compiler - Flags , die Sie verwenden. Unter jedem modernen UNIX erhalten Sie standardmäßig ein thread-sicheres Malloc. Unter Windows verwenden /MT, /MTd, /MDoder /MDdFahnen Thread-sichere Laufzeitbibliothek zu erhalten.

Angestellt Russisch
quelle
11
Wiedereintrittsroutinen können Sperren verwenden, solange die Sperre wiedereintrittsfähig ist. Dies erfordert, dass die Sperre in etwa einem rekursiven oder fehlerprüfenden Mutex entspricht, jedoch mit der zusätzlichen Bedingung, dass die einzelne atomare Operation, die die Sperre übernimmt, dazu führen muss, dass sich die Sperrenstruktur in einem konsistenten Zustand für eine neu gehaltene Sperre mit einer einzelnen befindet Referenz. Natürlich müssen Sie sich dann auch mit dem Fall befassen, in dem der durch die Sperre geschützte Status durch den unterbrochenen Code im selben Thread teilweise geändert wurde, aber dennoch wiedereintretende Sperren ein Baustein bei der Behandlung dieser ...
R sein können. GitHub STOP HELPING ICE
1
Ich glaube, / MT / MTd / MD usw. bedeutet nur, entweder Release / Debug / Dynamic oder statische CRT-Version zu verwenden, nicht dass Malloc threadsicher ist oder nicht (es ruft tatsächlich HeapAlloc auf, das ein optionales Flag ohne Serialisierung hat)
Paulm
13

Dies ist eine ziemlich alte Frage, und ich möchte dem aktuellen Stand der Dinge Frische verleihen.

Ja, ist derzeit malloc()threadsicher.

Aus dem GNU C Library Referenzhandbuch von glibc-2.20 [released 2014-09-07]:

void * malloc (size_t size)

Vorläufig: MT-Safe | ...

... 1.2.2.1 POSIX-Sicherheitskonzepte:

... MT-Safe- oder Thread-Safe-Funktionen können bei Vorhandensein anderer Threads sicher aufgerufen werden. MT steht in MT-Safe für Multi Thread.

MT-Safe zu sein bedeutet nicht, dass eine Funktion atomar ist oder einen der Speichersynchronisationsmechanismen verwendet, die POSIX Benutzern zur Verfügung stellt. Es ist sogar möglich, dass das Aufrufen von MT-Safe-Funktionen nacheinander keine MT-Safe-Kombination ergibt. Wenn ein Thread beispielsweise zwei MT-Safe-Funktionen direkt nacheinander aufruft, ist kein Verhalten garantiert, das der atomaren Ausführung einer Kombination beider Funktionen entspricht, da gleichzeitige Aufrufe in anderen Threads destruktiv stören können.

Optimierungen für das gesamte Programm, bei denen Funktionen über Bibliotheksschnittstellen hinweg integriert werden können, können zu unsicheren Neuordnungen führen. Daher wird das Inlining über die GNU C-Bibliotheksschnittstelle nicht empfohlen. Der dokumentierte MT-Sicherheitsstatus kann nicht für die Optimierung des gesamten Programms garantiert werden. In benutzerdefinierten Headern definierte Funktionen sind jedoch so konzipiert, dass sie für das Inlining sicher sind.

likern
quelle
9

Hier ist ein Auszug aus malloc.c von glibc:

Thread-Sicherheit: Thread-sicher, sofern nicht NO_THREADS definiert ist

Unter der Annahme, dass NO_THREADS nicht standardmäßig definiert ist, ist malloc zumindest unter Linux threadsicher.

Shahkhas
quelle
7

Ja, unter POSIX.1-2008 malloc ist threadsicher.

2.9.1 Gewindesicherheit

Alle in diesem Band von POSIX.1-2008 definierten Funktionen müssen threadsicher sein, mit der Ausnahme, dass die folgenden Funktionen1 nicht threadsicher sein müssen.

[eine Liste von Funktionen, die nicht enthält malloc]

Tanz87
quelle
7

Wenn Sie mit GLIBC arbeiten, lautet die Antwort: Ja, ABER.

Insbesondere, ja, ABER, bitte, bitte beachten Sie, dass malloc und free zwar threadsicher sind, die Debugging-Funktionen jedoch nicht.

Insbesondere sind die äußerst nützlichen Funktionen mtrace (), mcheck () und mprobe () nicht threadsicher . In einer der kürzesten und direktesten Antworten, die Sie jemals von einem GNU-Projekt erhalten werden, wird dies hier erklärt:

https://sourceware.org/bugzilla/show_bug.cgi?id=9939

Sie müssen alternative Techniken wie ElectricFence, Valgrind, Dmalloc usw. in Betracht ziehen.

Wenn Sie also meinen, "sind die Funktionen malloc () und free () threadsicher", lautet die Antwort "Ja". Aber wenn Sie meinen, "ist die gesamte malloc / free suite threadsicher", lautet die Antwort NEIN.

Haltepunkt
quelle
5

Kurze Antwort: Ja, ab C11, der ersten Version des C-Standards, die das Konzept von Threads enthält, müssen mallocFreunde threadsicher sein. Viele Betriebssysteme, die beide Threads und eine C-Laufzeit enthielten, haben diese Garantie lange vor dem C-Standard gegeben, aber ich bin nicht bereit, allen zu schwören . Allerdings mallocund Freunde sind nicht und nie aufgefordert wurden , einspringende zu sein.

Das heißt, es ist sicher, mehrere Threads gleichzeitig aufzurufen mallocund zu verwenden, freeohne sich Gedanken über das Sperren zu machen, solange Sie keine der anderen Regeln für die Speicherzuweisung verletzen (z. B. freeeinmal und nur einmal für jeden von zurückgegebenen Zeiger aufrufen malloc). Es ist jedoch nicht sicher, diese Funktionen von einem Signalhandler aus aufzurufen, der möglicherweise einen Aufruf an mallocoder freein dem Thread, der das Signal verarbeitet, unterbrochen hat . Wenn Sie Funktionen verwenden, die über ISO C hinausgehen, können Sie manchmal sicherstellen, dass der Thread, der das Signal verarbeitet, einen Aufruf von mallocoder free, z. B. mit sigprocmaskund sigpause, nicht unterbrochen hat. Versuchen Sie dies jedoch nicht, es sei denn, Sie haben keine andere Option, da es schwierig ist, die richtigen Ergebnisse zu erzielen.


Lange Antwort mit Zitaten: Der C-Standard hat in der Überarbeitung von 2011 ein Thread-Konzept hinzugefügt (Link führt zum Dokument N1570, das dem offiziellen Text des 2011-Standards, der kostenlos öffentlich verfügbar ist, am nächsten kommt). In dieser Überarbeitung heißt es in Abschnitt 7.1.4 Absatz 5 :

Sofern in den folgenden detaillierten Beschreibungen nicht ausdrücklich anders angegeben, verhindern Bibliotheksfunktionen Datenrennen wie folgt: Eine Bibliotheksfunktion darf nicht direkt oder indirekt auf Objekte zugreifen, auf die andere Threads als der aktuelle Thread zugreifen, es sei denn, auf die Objekte wird direkt oder indirekt über die Argumente der Funktion zugegriffen . Eine Bibliotheksfunktion darf keine Objekte direkt oder indirekt ändern, auf die andere Threads als der aktuelle Thread zugreifen können, es sei denn, auf die Objekte wird direkt oder indirekt über die nicht konstanten Argumente der Funktion zugegriffen. Implementierungen können ihre eigenen internen Objekte zwischen Threads gemeinsam nutzen, wenn die Objekte für Benutzer nicht sichtbar und vor Datenrennen geschützt sind.

[Fußnote: Dies bedeutet beispielsweise, dass eine Implementierung ein statisches Objekt ohne Synchronisierung nicht für interne Zwecke verwenden darf, da dies selbst in Programmen, die Objekte nicht explizit zwischen Threads gemeinsam nutzen, zu einem Datenrennen führen kann. Ebenso ist es einer Implementierung von memcpy nicht gestattet, Bytes über die angegebene Länge des Zielobjekts hinaus zu kopieren und dann die ursprünglichen Werte wiederherzustellen, da dies zu einem Datenrennen führen kann, wenn das Programm diese Bytes zwischen Threads teilt.]

Soweit ich weiß, ist dies eine langwierige Art zu sagen, dass die durch den C-Standard definierten Bibliotheksfunktionen threadsicher sein müssen (im üblichen Sinne: Sie können sie von mehreren Threads gleichzeitig aufrufen, ohne sich selbst zu sperren , solange sie nicht mit den als Argumente übergebenen Daten in Konflikt geraten), es sei denn, die Dokumentation für eine bestimmte Funktion besagt ausdrücklich, dass dies nicht der Fall ist.

Dann bestätigt 7.22.3p2 , dass malloc, calloc, realloc, align_alloc und insbesondere free threadsicher sind:

Um die Existenz eines Datenrennens zu bestimmen, verhalten sich Speicherzuweisungsfunktionen so, als hätten sie nur auf Speicherorte zugegriffen, auf die über ihre Argumente zugegriffen werden kann, und nicht auf andere Speicher mit statischer Dauer. Diese Funktionen können jedoch den von ihnen zugewiesenen oder freigegebenen Speicher sichtbar ändern. Ein Aufruf zum Freigeben oder Neuzuweisen, der die Zuweisung einer Region p des Speichers aufhebt, wird mit jedem Zuweisungsaufruf synchronisiert, der die Region p ganz oder teilweise zuweist. Diese Synchronisation erfolgt nach jedem Zugriff von p durch die Freigabefunktion und vor einem solchen Zugriff durch die Zuweisungsfunktion.

Kontrast , was es sagt über strtok, was nicht und nie ist gewesen Thread-sicher, in 7.24.5.8p6 :

Die strtok-Funktion ist nicht erforderlich, um Datenrennen mit anderen Aufrufen der strtok-Funktion zu vermeiden.

[Fußnote: Die Funktion strtok_s kann stattdessen verwendet werden, um Datenrennen zu vermeiden.]

(Kommentar zur Fußnote: nicht verwenden strtok_s, verwenden strsep.)

Ältere Versionen des C-Standards sagten überhaupt nichts über die Gewindesicherheit aus. Aber sie tat sagt etwas über reentrancy, weil Signale immer einen Teil des C Standard. Und dies ist, was sie sagten und auf den ursprünglichen ANSI C-Standard von 1989 zurückgingen (dieses Dokument hat einen nahezu identischen Wortlaut, unterscheidet sich jedoch stark von der Abschnittsnummerierung des ISO C-Standards, der im folgenden Jahr herauskam):

Wenn ein [a] -Signal nicht als Ergebnis des Aufrufs der Abbruch- oder Erhöhungsfunktion auftritt, ist das Verhalten undefiniert, wenn der Signalhandler eine andere Funktion in der Standardbibliothek als die Signalfunktion selbst aufruft oder auf ein Objekt mit einer anderen statischen Speicherdauer verweist als durch Zuweisen eines Werts zu einer statischen Speicherdauervariablen vom Typ flüchtig sig_atomic_t. Wenn ein solcher Aufruf der Signalfunktion zu einer SIG_ERR-Rückgabe führt, ist der Wert von errno unbestimmt.

Das ist eine langatmige Art zu sagen , dass C - Bibliotheksfunktionen sind nicht einspringenden als allgemeine Regel sein , erforderlich. Ein sehr ähnlicher Wortlaut erscheint immer noch in C11, 7.14.1.1p5 :

Wenn ein [a] -Signal nicht als Ergebnis des Aufrufs der Abbruch- oder Erhöhungsfunktion auftritt, ist das Verhalten undefiniert, wenn der Signalhandler auf ein Objekt mit statischer oder Thread-Speicherdauer verweist, das kein sperrfreies atomares Objekt ist, außer durch Zuweisen Ein Wert für ein als flüchtig deklariertes Objekt sig_atomic_t oder der Signalhandler ruft eine andere Funktion in der Standardbibliothek als die Abbruchfunktion, die _Exit-Funktion, die quick_exit-Funktion oder die Signalfunktion auf, wobei das erste Argument der entsprechenden Signalnummer entspricht das Signal, das den Aufruf des Handlers verursacht hat. Wenn ein solcher Aufruf der Signalfunktion zu einer SIG_ERR-Rückgabe führt, ist der Wert von errno unbestimmt.

[Fußnote: Wenn ein Signal von einem asynchronen Signalhandler generiert wird, ist das Verhalten undefiniert.]

POSIX erfordert eine viel längere, aber im Vergleich zur Gesamtgröße der C-Bibliothek immer noch kurze Liste von Funktionen, die von einem "asynchronen Signalhandler" sicher aufgerufen werden können, und definiert auch detaillierter die Umstände, unter denen ein Signal "anders auftreten kann" als Ergebnis des Aufrufs der Abbruch- oder Erhöhungsfunktion. " Wenn Sie mit Signalen etwas nicht Triviales tun, schreiben Sie wahrscheinlich Code, der auf einem Betriebssystem mit Unix-Charakter ausgeführt werden soll (im Gegensatz zu Windows, MVS oder etwas Eingebettetem, das wahrscheinlich keine vollständig gehostete Implementierung von C in hat an erster Stelle), und Sie sollten sich mit den POSIX-Anforderungen für sie sowie den ISO C-Anforderungen vertraut machen.

zwol
quelle
1

Dies hängt davon ab, welche Implementierung der C-Laufzeitbibliothek Sie verwenden. Wenn Sie beispielsweise MSVC verwenden, gibt es eine Compileroption, mit der Sie angeben können, mit welcher Version der Bibliothek Sie erstellen möchten (dh eine Laufzeitbibliothek, die Multithreading unterstützt, indem sie für das Profil sicher ist oder nicht).

ChrisW
quelle
1

Nein, es ist nicht threadsicher. Möglicherweise ist in Ihrer C-Bibliothek tatsächlich eine malloc_lock()und- malloc_unlock()Funktion verfügbar. Ich weiß, dass diese für die Newlib-Bibliothek existieren. Ich musste dies verwenden, um einen Mutex für meinen Prozessor zu implementieren, der in der Hardware über mehrere Threads verfügt.

Sybreon
quelle
5
Jede Implementierung von malloc auf einem System, das einem wichtigen Thread-Standard (wie POSIX) entspricht, ist threadsicher.
R .. GitHub STOP HELPING ICE
1

malloc und free sind nicht wiedereintrittsfähig, da sie eine statische Datenstruktur verwenden, die aufzeichnet, welche Speicherblöcke frei sind. Infolgedessen sind keine Bibliotheksfunktionen, die Speicher zuweisen oder freigeben, wiedereintrittsfähig.

user3379688
quelle
0

Nein ist es nicht.

Webarchiv-Link (Original ist tot)

Paul Sonier
quelle
2
Wie unter groups.google.com/group/comp.lang.c.moderated/browse_thread/… angegeben , ist dies nicht unbedingt korrekt. malloc ist weder garantiert noch garantiert threadsicher. Es ist implementierungsabhängig.
Matthew Flaschen
2
Sicherheit ist nicht teilweise; Wenn eine Implementierung möglicherweise nicht sicher ist, ist meine Interpretation, dass sie nicht sicher ist. Das Poster hat keine Plattform angegeben. Daher kann keine Sicherheitsgarantie gegeben werden.
Paul Sonier
5
Jede Implementierung ist entweder sicher oder nicht sicher. Zu sagen, dass eine unbekannte Implementierung unsicher ist, ist nicht wahrer als zu sagen, dass sie sicher ist. Die richtige Antwort ist, dass es implementierungsabhängig ist.
ChrisW
3
@ChrisW: Da das OP die Implementierung nicht spezifiziert hat und Sicherheit eine absolute Bedingung ist (sie kann mit nur einer Ausnahme gebrochen werden; nur eine unsichere Aktion kann etwas "unsicher" machen), habe ich beschlossen zu antworten, dass sie unsicher ist. Das Originalplakat kann für sich selbst bestimmen, was die richtige Antwort ist.
Paul Sonier
3
@ChrisW - Russisches Roulette ist sicher.
Oktalist
0

Ich schlage vor zu lesen

§31.1 Gewindesicherheit (und Wiedereintritt überarbeitet)

des Buches The Linux Programming Interface erklärt den Unterschied zwischen Thread-Sicherheit und Wiedereintritt sowie malloc.

Auszug:

Eine Funktion gilt als threadsicher, wenn sie von mehreren Threads gleichzeitig sicher aufgerufen werden kann. Umgekehrt, wenn eine Funktion nicht threadsicher ist, können wir sie nicht von einem Thread aus aufrufen, während sie in einem anderen Thread ausgeführt wird.

....
Diese Funktion zeigt den typischen Grund, warum eine Funktion nicht threadsicher ist: Sie verwendet globale oder statische Variablen, die von allen Threads gemeinsam genutzt werden.

...
Obwohl die Verwendung kritischer Abschnitte zur Implementierung der Thread-Sicherheit eine erhebliche Verbesserung gegenüber der Verwendung von Mutexen pro Funktion darstellt, ist sie dennoch etwas ineffizient, da das Sperren und Entsperren eines Mutex mit Kosten verbunden ist. Eine Wiedereintrittsfunktion erreicht die Gewindesicherheit ohne die Verwendung von Mutexen. Dies geschieht, indem die Verwendung globaler und statischer Variablen vermieden wird.

... Es können
jedoch nicht alle Funktionen wiedereintrittsfähig gemacht werden. Die üblichen Gründe sind folgende:

  • Einige Funktionen müssen naturgemäß auf globale Datenstrukturen zugreifen. Die Funktionen in der Malloc-Bibliothek sind ein gutes Beispiel. Diese Funktionen führen eine global verknüpfte Liste freier Blöcke auf dem Heap. Die Funktionen der mallocBibliothek werden durch die Verwendung von Mutexen threadsicher gemacht.

....

Auf jeden Fall eine Lektüre wert.

Und um Ihre Frage zu beantworten, mallocist threadsicher, aber nicht wiedereintrittsfähig.

Rick
quelle