Malloc è sicuro per i thread?

La funzione malloc() ri-entra?

Ho letto da qualche parte che se si compila con -pthread, malloc diventa thread safe. Sono abbastanza sicuro che dipenda dall’implementazione, dal momento che malloc è ANSI C e thread no.

Se stiamo parlando di gcc:

Compila e collega con -pthread e malloc () sarà thread-safe, su x86 e AMD64.

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

Un’altra opinione, più perspicace

{malloc, calloc, realloc, free, posix_memalign} di glibc-2.2 + sono thread-safe

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

Domanda: “è malloc reentrant”?
Risposta: no, non lo è. Ecco una definizione di ciò che rende un rientro di routine.

Nessuna delle versioni comuni di malloc ti consente di reinserirle (ad es. Da un gestore di segnale). Si noti che una routine rientrante non può utilizzare i lock e quasi tutte le versioni di malloc in uso utilizzano i lock (che li rendono thread-safe) o le variabili globali / statiche (il che li rende thread-safe e non-reentrant).

Tutte le risposte finora risposta “è malloc thread-safe?”, Che è una domanda completamente diversa. A questa domanda la risposta dipende dalla tua libreria di runtime e probabilmente dai flag del compilatore che usi. Su qualsiasi UNIX moderno, avrai un malloc sicuro per i thread di default. Su Windows, usa i /MTd /MT , /MTd , /MD o /MDd per ottenere la libreria di runtime sicura per i thread.

Ecco un estratto da malloc.c di glibc:

Filo-sicurezza: thread-safe a meno che NO_THREADS sia definito

supponendo che NO_THREADS non sia definito di default, malloc è thread safe almeno su linux.

Questa è una domanda abbastanza vecchia e voglio portare freschezza secondo lo stato attuale delle cose.

Sì, attualmente malloc() è thread-safe.

Dal manuale di riferimento della libreria GNU C di glibc-2.20 [released 2014-09-07] :

void * malloc (size_t size)

Preliminare: MT-Safe | …

… 1.2.2.1 Concetti di sicurezza POSIX:

… Le funzioni MT-Safe o Thread-Safe sono sicure per chiamare in presenza di altri thread. MT, in MT-Safe, sta per Multi Thread.

Essere MT-Safe non implica che una funzione sia atomica, né che utilizzi nessuno dei meccanismi di sincronizzazione della memoria che POSIX espone agli utenti. È anche ansible che chiamare le funzioni MT-Safe in sequenza non produca una combinazione MT-Safe. Ad esempio, avere una chiamata di thread due funzioni MT-Safe una dopo l’altra non garantisce un comportamento equivalente all’esecuzione atomica di una combinazione di entrambe le funzioni, poiché le chiamate simultanee in altri thread potrebbero interferire in modo distruttivo.

Le ottimizzazioni di interi programmi che potrebbero incorporare le funzioni tra le interfacce della libreria potrebbero esporre il riordinamento non sicuro, pertanto non è consigliabile eseguire l’inlining nell’interfaccia GNU C Library. Lo stato di MT-Safety documentato non è garantito dall’ottimizzazione del programma underwhole. Tuttavia, le funzioni definite nelle intestazioni user-visible sono progettate per essere sicure per l’inlining.

Sì, in POSIX.1-2008 malloc è thread-safe.

2.9.1 Sicurezza del filo

Tutte le funzioni definite da questo volume di POSIX.1-2008 devono essere thread-safe, eccetto che le seguenti funzioni1 non devono essere thread-safe.

[un elenco di funzioni che non contengono malloc ]

Se stai lavorando con GLIBC, la risposta è: Sì, MA.

In particolare, sì, MA, per favore, tieni presente che mentre malloc e free sono thread-safe, le funzioni di debug non lo sono.

Nello specifico, le funzioni estremamente utili mtrace (), mcheck () e mprobe () non sono thread-safe . In una delle risposte più brevi e diritte che tu possa mai vedere da un progetto GNU, questo è spiegato qui:

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

Dovrai considerare tecniche alternative come ElectricFence, valgrind, dmalloc, ecc.

Quindi, se vuoi dire “sono le funzioni malloc () e free () threadsafe”, la risposta è sì. Ma se vuoi dire “è l’intero malloc / free suite threadsafe”, la risposta è NO.

Dipende dall’implementazione della libreria di runtime C che stai utilizzando. Ad esempio, se si utilizza MSVC, è disponibile un’opzione per il compilatore che consente di specificare la versione della libreria che si desidera creare (ovvero una libreria di runtime che supporta il multithreading in modo da essere sicura o meno).

No, non è thread-safe. Potrebbe esserci effettivamente una funzione malloc_lock() e malloc_unlock() disponibile nella libreria C. So che esistono per la libreria Newlib. Ho dovuto usarlo per implementare un mutex per il mio processore, che è multi-thread in hardware.

malloc e free non sono rientranti, perché usano una struttura di dati statici che registra quali blocchi di memoria sono liberi. Di conseguenza, nessuna funzione di libreria che assegna o libera memoria è rientrante.

Risposta breve: sì, a partire da C11, che è la prima versione dello standard C che include il concetto di thread, malloc e gli amici devono essere thread-safe. Molti sistemi operativi che includevano sia i thread che un runtime C hanno reso questa garanzia molto prima dello standard C, ma non sono pronto a giurare a tutti . Tuttavia, malloc e gli amici non sono e non è mai stato richiesto di essere rientranti.

Ciò significa che è sicuro chiamare malloc e free da più thread simultaneamente e non preoccuparti del blocco, a condizione che tu non infranga nessuna delle altre regole di allocazione della memoria (ad es. Chiama free una volta e solo una volta su ogni puntatore restituito da malloc ). Ma non è sicuro chiamare queste funzioni da un gestore di segnale che potrebbe aver interrotto una chiamata a malloc o free nella thread che gestisce il segnale. A volte, usando funzionalità oltre ISO C, puoi garantire che il thread che gestisce il segnale non interrompa una chiamata a malloc o free , ad esempio con sigprocmask e sigpause , ma cerca di non farlo a meno che tu non abbia altra opzione, perché è difficile avere perfettamente ragione.


Risposta lunga con citazioni: lo standard C ha aggiunto un concetto di thread nella revisione del 2011 (il link è di documentare N1570, che è l’approssimazione più vicina al testo ufficiale dello standard del 2011 che è pubblicamente disponibile gratuitamente). In quella revisione, la sezione 7.1.4 paragrafo 5 afferma:

A meno che non sia esplicitamente indicato diversamente nelle descrizioni dettagliate che seguono, le funzioni della libreria impediscono la corsa dei dati come segue: Una funzione di libreria non accede direttamente o indirettamente agli oggetti accessibili da thread diversi dal thread corrente a meno che gli oggetti siano accessibili direttamente o indirettamente tramite gli argomenti della funzione . Una funzione di libreria non modifica direttamente o indirettamente oggetti accessibili da thread diversi dal thread corrente a meno che gli oggetti non siano accessibili direttamente o indirettamente tramite gli argomenti non-const della funzione. Le implementazioni possono condividere i propri oggetti interni tra i thread se gli oggetti non sono visibili agli utenti e sono protetti dalle gare di dati.

[nota a piè di pagina: questo significa, ad esempio, che un’implementazione non è autorizzata a utilizzare un object statico per scopi interni senza sincronizzazione perché potrebbe causare una corsa di dati anche in programmi che non condividono esplicitamente oggetti tra thread. Allo stesso modo, un’implementazione di memcpy non è consentita per copiare byte oltre la lunghezza specificata dell’object di destinazione e quindi ripristinare i valori originali perché potrebbe causare una corsa di dati se il programma li condivide tra i thread.]

A quanto ho capito, questo è un modo prolisso per dire che le funzioni della libreria definite dallo standard C devono essere thread-safe (nel senso comune: puoi chiamarle da più thread contemporaneamente, senza bloccarti tu stesso , a patto che non finiscano a scontrarsi con i dati passati come argomenti) a meno che la documentazione per una funzione specifica non dica esplicitamente di non farlo.

Quindi, 7.22.3p2 conferma che malloc, calloc, realloc, aligned_alloc e free, in particolare, sono thread-safe:

Ai fini della determinazione dell’esistenza di una corsa di dati, le funzioni di allocazione della memoria si comportano come se accedessero solo alle posizioni di memoria accessibili attraverso i loro argomenti e non altre memorie di durata statica. Queste funzioni possono tuttavia modificare visibilmente lo spazio di archiviazione che allocano o deallocano. Una chiamata a free o realloc che rilascia una regione p di memoria si sincronizza con qualsiasi chiamata di allocazione che alloca tutto o parte della regione p. Questa sincronizzazione si verifica dopo qualsiasi accesso di p dalla funzione deallocating e prima di qualsiasi accesso di questo dalla funzione di allocazione.

Contrasta ciò che dice su strtok, che non è e non è mai stato thread-safe, in 7.24.5.8p6 :

La funzione strtok non è necessaria per evitare la corsa dei dati con altre chiamate alla funzione strtok.

[nota a piè di pagina: la funzione strtok_s può essere utilizzata al posto di evitare le corse di dati.]

(commento sulla nota: non usare strtok_s , usare strsep .)

Versioni precedenti dello standard C non dicevano assolutamente nulla sulla sicurezza del filo. Tuttavia, hanno detto qualcosa sulla rientranza, perché i segnali hanno sempre fatto parte dello standard C. E questo è quello che hanno detto, tornando allo standard ANSI C originale del 1989 (questo documento ha una dicitura quasi identica a, ma una numerazione delle sezioni molto diversa rispetto allo standard ISO C uscito l’anno seguente):

Se il segnale [a] si verifica non come risultato del richiamo della funzione abort o raise, il comportamento non è definito se il gestore di segnale chiama qualsiasi funzione nella libreria standard diversa dalla funzione di segnale stessa o fa riferimento a qualsiasi object con durata di memorizzazione statica altro che assegnando un valore a una variabile di durata di memorizzazione statica di tipo volatile sig_atomic_t. Inoltre, se tale richiamo alla funzione di segnale produce un ritorno SIG_ERR, il valore di errno è indeterminato.

Il che è un modo prolisso per dire che le funzioni della libreria C non devono essere rientranti come regola generale. Formulazione molto simile appare ancora in C11, 7.14.1.1p5 :

Se il segnale [a] si verifica a parte il risultato di chiamare la funzione abort o raise, il comportamento non è definito se il gestore di segnale fa riferimento a qualsiasi object con durata di memorizzazione statica o thread che non è un object atomico privo di blocco diverso dall’assegnazione un valore per un object dichiarato come sig_atomic_t volatile, oppure il gestore di segnale chiama qualsiasi funzione nella libreria standard diversa dalla funzione abort, la funzione _Exit, la funzione quick_exit o la funzione signal con il primo argomento uguale al numero del segnale corrispondente a il segnale che ha causato l’invocazione del conduttore. Inoltre, se tale richiamo alla funzione di segnale produce un ritorno SIG_ERR, il valore di errno è indeterminato.

[nota in calce: se un segnale è generato da un gestore di segnale asincrono, il comportamento non è definito.]

POSIX richiede un tempo molto più lungo, ma ancora breve rispetto alla dimensione complessiva della libreria C , l’elenco delle funzioni può essere tranquillamente richiamabile da un “gestore di segnale asincrono” e definisce anche più in dettaglio le circostanze in cui un segnale potrebbe “verificarsi” piuttosto che il risultato di chiamare l’interruzione o alzare la funzione. ” Se stai facendo qualcosa di non banale con i segnali, probabilmente stai scrivendo codice destinato a essere eseguito su un sistema operativo con la natura Unix (al contrario di Windows, MVS o qualcosa di incorporato che probabilmente non ha un’implementazione hosted completa di C in il primo posto) e dovresti familiarizzare con i requisiti POSIX per loro, così come con i requisiti ISO C.