2012-05-22 11 views
42

Il tipico malloc (per piattaforma x86-64 e SO Linux) blocca in modo ingannevole un mutex all'inizio e lo rilascia al termine, oppure blocca un mutex in un modo più intelligente ad un livello più fine, in modo che la contesa del blocco sia ridotto? Se effettivamente lo fa il secondo modo, come lo fa?Come funziona malloc in un ambiente con multithreading?

+0

Qual è il contesto in cui hai visto questo? Qualsiasi codice citato o riferimento? – Raulp

+5

dolcemente: sto chiedendo, non dicendo. – pythonic

+0

Devo commentare che ci sono alternative migliori a malloc quando si usa un ambiente multi-thread, usare google –

risposta

35

glibc 2.15 gestisce più assegnazioni arene. Ogni arena ha il suo lucchetto. Quando un thread deve allocare memoria, malloc() preleva un'arena, la blocca e ne assegna la memoria.

Il meccanismo per la scelta di un'arena è in qualche modo elaborato e mira a ridurre il conflitto di blocchi:

/* arena_get() acquires an arena and locks the corresponding mutex. 
    First, try the one last locked successfully by this thread. (This 
    is the common case and handled with a macro for speed.) Then, loop 
    once over the circularly linked list of arenas. If no arena is 
    readily available, create a new one. In this latter case, `size' 
    is just a hint as to how much memory will be required immediately 
    in the new arena. */ 

Con questo in mente, malloc() fondamentalmente si presenta così (modificati per brevità):

mstate ar_ptr; 
    void *victim; 

    arena_lookup(ar_ptr); 
    arena_lock(ar_ptr, bytes); 
    if(!ar_ptr) 
    return 0; 
    victim = _int_malloc(ar_ptr, bytes); 
    if(!victim) { 
    /* Maybe the failure is due to running out of mmapped areas. */ 
    if(ar_ptr != &main_arena) { 
     (void)mutex_unlock(&ar_ptr->mutex); 
     ar_ptr = &main_arena; 
     (void)mutex_lock(&ar_ptr->mutex); 
     victim = _int_malloc(ar_ptr, bytes); 
     (void)mutex_unlock(&ar_ptr->mutex); 
    } else { 
     /* ... or sbrk() has failed and there is still a chance to mmap() */ 
     ar_ptr = arena_get2(ar_ptr->next ? ar_ptr : 0, bytes); 
     (void)mutex_unlock(&main_arena.mutex); 
     if(ar_ptr) { 
     victim = _int_malloc(ar_ptr, bytes); 
     (void)mutex_unlock(&ar_ptr->mutex); 
     } 
    } 
    } else 
    (void)mutex_unlock(&ar_ptr->mutex); 

    return victim; 

Questo allocatore si chiama ptmalloc. È basato su earlier work di Doug Lea ed è gestito da Wolfram Gloger.

19

Doug Lea's malloc utilizzato bloccaggio grossolana (o nessun blocco, a seconda delle impostazioni di configurazione), dove ogni chiamata a malloc/realloc/free è protetto da un mutex globale. Questo è sicuro ma può essere inefficiente in ambienti ad alto multithreading.

ptmalloc3, che è l'implementazione predefinita malloc nella libreria GNU C (libc) utilizzato in molti sistemi Linux questi giorni, ha una strategia più a grana fine, come descritto in aix's answer, che consente più thread per allocare contemporaneamente memoria sicuro .

nedmalloc è un'altra implementazione indipendente che richiede prestazioni multithreading ancora migliori rispetto a ptmalloc3 e vari altri allocatori. Non so come funzioni, e non sembra esserci alcuna documentazione ovvia, quindi dovrai controllare il codice sorgente per vedere come funziona.

+1

Sono ancora indeciso se nedmalloc è una vera impresa ingegneristica o SEO spam ... :-) –

+0

anche tcmalloc da google che utilizza serrature su serbatoi dimensionati secondo la tua richiesta. Migliori prestazioni del thread con meno contesa, più allocazione in eccesso. –

+0

@R ..: A prima vista sembra un po 'sospetto, ma ha il codice sorgente in modo da poterlo confrontare (non l'ho fatto). Doug Lea dice anche "Se stai usando malloc in un programma concorrente, considera invece di usare nedmalloc o ptmalloc" nei commenti per 'dlmalloc.c'. Quindi penso che sia probabilmente legittimo. –

Problemi correlati