La fonction malloc()
est-elle ré-entrante?
J'ai lu quelque part que si vous compilez avec -pthread, malloc devient thread-safe. Je suis à peu près sûr que sa mise en œuvre dépend de Malloc, car ANSI C est utilisé, et les threads ne le sont pas.
Si nous parlons de gcc:
Compiler et lier avec -pthread et malloc () sera thread-safe, sur x86 et AMD64.
Un autre avis, plus perspicace
{malloc, calloc, realloc, gratuit, posix_memalign} de la glibc-2.2 + sont fil sécuritaire
http://linux.derkeiler.com/Newsgroups/comp.os.linux.development.apps/2005-07/0323.html
Question: "le malloc est-il réentrant"?
Réponse: non, ce n'est pas. Voici une définition de ce qui fait une routine réentrant .
Aucune des versions courantes de malloc ne vous permet de la ressaisir (par exemple à partir d'un gestionnaire de signal). Notez qu'une routine réentrante ne peut pas utiliser de verrous, et presque toutes les versions existantes de malloc utilisent des verrous (ce qui les rend thread-safe), ou des variables globales/statiques (ce qui les rend thread-unsafe et non réentrant) .
Jusqu'à présent, toutes les réponses répondent "est-ce que malloc est thread-safe?", Ce qui est une question totalement différente. Pour that question, la réponse est cela dépend de votre bibliothèque d'exécution, et éventuellement des indicateurs de compilation que vous utilisez. Sous UNIX moderne, vous obtiendrez un malloc thread-safe par défaut. Sous Windows, utilisez les indicateurs /MT
, /MTd
, /MD
et /MDd
pour obtenir la bibliothèque d'exécution thread-safe.
Voici un extrait de malloc.c de glibc:
Sécurité des threads: thread-safe sauf si NO_THREADS est défini
en supposant que NO_THREADS n'est pas défini par défaut, malloc est thread-safe au moins sur Linux.
Oui, sous POSIX.1-2008malloc
est thread-safe.
2.9.1 Sécurité du fil
Toutes les fonctions définies par ce volume de POSIX.1-2008 doivent être thread-safe, sauf que les fonctions suivantes1 ne doivent pas nécessairement l'être.
[une liste de fonctions qui ne contient pas
malloc
]
Si vous travaillez avec GLIBC, la réponse est: Oui, MAIS.
Plus précisément, oui, MAIS merci de noter que bien que malloc et free soient thread-safe, les fonctions de débogage ne le sont pas.
Plus précisément, les fonctions extrêmement utiles de mtrace (), mcheck () et mprobe () ne sont pas thread-safe. Dans l'une des réponses les plus courtes et les plus directes que vous aurez jamais vu avec un projet GNU, ceci est expliqué ici:
https://sourceware.org/bugzilla/show_bug.cgi?id=9939
Vous devrez envisager d’autres techniques, telles que ElectricFence, Valgrind, Dmalloc, etc.
Donc, si vous voulez dire "sont les fonctions threadsafe malloc () et free ()", la réponse est oui. Mais si vous voulez dire, "est tout le malloc/free suite threadsafe", la réponse est NON.
Non, ce n'est pas thread-safe. Il peut en fait y avoir une fonction malloc_lock()
et malloc_unlock()
disponible dans votre bibliothèque C. Je sais que ceux-ci existent pour la bibliothèque Newlib. Je devais l'utiliser pour implémenter un mutex pour mon processeur multi-thread dans le matériel.
malloc et free ne sont pas réentrants, car ils utilisent une structure de données statique qui enregistre les blocs de mémoire libres. En conséquence, aucune fonction de bibliothèque allouant ou libérant de la mémoire n'est réentrante.
Cela dépend de l’implémentation de la bibliothèque d’exécution C que vous utilisez. Si vous utilisez MSVC par exemple, il existe une option de compilation qui vous permet de spécifier la version de la bibliothèque avec laquelle vous voulez construire (c'est-à-dire une bibliothèque d'exécution prenant en charge le multi-threading en étant protégé ou non).
Réponse courte: oui, à partir de C11, qui est la première version de la norme C qui inclut le concept de threads, malloc
et amis doivent être thread-safe. De nombreux systèmes d'exploitation comprenant à la fois des threads et une exécution C ont déjà fait cette garantie bien avant la norme C, mais je ne suis pas prêt à jurer de (toutes). Cependant, malloc
et ses amis ne sont pas et n’ont jamais été obligés d’être réentrants.
Cela signifie que vous pouvez appeler malloc
et free
à partir de plusieurs threads simultanément sans vous soucier du verrouillage, tant que vous ne respectez pas l'une des autres règles d'allocation de mémoire (par exemple, appelez free
une et une seule fois sur chaque pointeur renvoyé par malloc
). Mais il est non sûr d'appeler ces fonctions depuis un gestionnaire de signal qui aurait pu interrompre un appel à malloc
ou free
dans le thread qui gère le signal. Parfois, en utilisant une fonctionnalité au-delà de la norme ISO C, vous pouvez garantir que le thread qui traite le signal n’a pas interrompu un appel de malloc
ou free
, par exemple. avec sigprocmask
et sigpause
, mais essayez de ne le faire que si vous n'avez pas d'autre choix, car il est difficile d'obtenir un résultat parfait.
Réponse longue avec citations: la norme C a ajouté un concept de threads dans la révision 2011 (le lien renvoie au document N1570, qui est l’approximation la plus proche du texte officiel de la norme de 2011, accessible gratuitement au public). Dans cette révision, section 7.1.4, paragraphe 5 stipule:
Sauf indication contraire explicite dans les descriptions détaillées qui suivent, les fonctions de bibliothèque doivent empêcher les courses de données comme suit: Une fonction de bibliothèque ne doit pas accéder directement ou indirectement à des objets accessibles par des threads autres que le thread actuel, à moins que les objets ne soient accessibles directement ou indirectement via les arguments de la fonction. . Une fonction de bibliothèque ne doit pas modifier directement ou indirectement des objets accessibles par des fils autres que le fil actuel, à moins que les objets ne soient accessibles directement ou indirectement via les arguments non const de la fonction. Les implémentations peuvent partager leurs propres objets internes entre les threads si les objets ne sont pas visibles par les utilisateurs et sont protégés contre les courses de données.
[note en bas de page: cela signifie, par exemple, qu'une implémentation n'est pas autorisée à utiliser un objet statique à des fins internes sans synchronisation, car cela pourrait provoquer une course de données, même dans les programmes qui ne partagent pas explicitement des objets entre les threads. De même, une implémentation de memcpy n'est pas autorisée à copier des octets au-delà de la longueur spécifiée de l'objet de destination, puis à restaurer les valeurs d'origine, car cela pourrait provoquer une course de données si le programme partageait ces octets entre les threads.]
Si je comprends bien, c’est une façon longue de dire que les fonctions de bibliothèque définies par le standard C doivent être thread-safe (au sens habituel: vous pouvez les appeler simultanément depuis plusieurs threads, sans vous verrouiller vous-même. , tant qu’ils ne finissent pas par s’affronter sur les données transmises en tant qu’arguments) à moins que la documentation d’une fonction spécifique ne le spécifie pas.
Ensuite, 7.22.3p2 confirme que malloc, calloc, realloc, aligné_alloc et free en particulier sont thread-safe:
Afin de déterminer l'existence d'une course de données, les fonctions d'allocation de mémoire se comportent comme si elles n'avaient accès qu'à des emplacements de mémoire accessibles par leurs arguments et non à un autre stockage de durée statique. Ces fonctions peuvent toutefois modifier de manière visible le stockage qu'elles allouent ou désallouent. Un appel à free ou realloc qui libère une région p de la mémoire se synchronise avec tout appel d’allocation qui alloue tout ou partie de la région p. Cette synchronisation a lieu après tout accès de p par la fonction de désallocation, et avant tout accès de ce type par la fonction d'allocation.
Contrastez ce qu'il dit à propos de strtok, qui n'est pas et n'a jamais été thread-safe, dans 7.24.5.8p6 :
La fonction strtok n'est pas nécessaire pour éviter les courses de données avec d'autres appels à la fonction strtok.[note en bas de page: la fonction strtok_s peut être utilisée à la place pour éviter les courses de données.].
(commentaire sur la note de bas de page: n'utilisez pas
strtok_s
, utilisezstrsep
.)
Les anciennes versions de la norme C ne disaient absolument rien sur la sécurité des threads. Cependant, ils ont parlent de la réentrance, car les signaux ont toujours fait partie de la norme C. Et voici ce qu’ils ont dit, en revenant à la norme ANSI C originale de 1989 = [(ce document a un libellé presque identique à celui de la norme ISO C, mais une numérotation très différente de celle-ci, parue l'année suivante):
Ce qui est une façon longue de dire que les fonctions de la bibliothèque C sont non requises pour être réentrantes en règle générale. Un libellé très similaire apparaît toujours dans C11, 7.14.1.1p5 :.
[note en bas de page: Si un signal est généré par un gestionnaire de signal asynchrone, le comportement est indéfini.].
POSIX nécessite un beaucoup plus long, mais toujours court comparé à la taille globale de la bibliothèque C , une liste de fonctions pouvant être appelées en toute sécurité à partir d'un "gestionnaire de signal asynchrone", et définissant plus en détail les circonstances dans lesquelles un signal peut "se produire autrement que par suite de l'appel de la fonction d'abandon ou de relance". Si vous faites quelque chose de non trivial avec des signaux, vous écrivez probablement du code destiné à être exécuté sur un système d'exploitation de type Unix (par opposition à Windows, MVS ou quelque chose d’embarqué qui ne possède probablement pas une implémentation hébergée complète de C dans en premier lieu), et vous devez vous familiariser avec les exigences POSIX, ainsi qu’avec les exigences ISO C.
POSIX requires a much longer, but still short compared to the overall size of the C library , list of functions to be safely callable from an "asynchronous signal handler", and also defines in more detail the circumstances under which a signal might "occur other than as the result of calling the abort or raise function." If you're doing anything nontrivial with signals, you are probably writing code intended to be run on an OS with the Unix nature (as opposed to Windows, MVS, or something embedded that probably doesn't have a complete hosted implementation of C in the first place), and you should familiarize yourself with the POSIX requirements for them, as well as the ISO C requirements.