2012-05-22 16 views
42

El típico malloc (para la plataforma x86-64 y el sistema operativo Linux) bloquea ingenuamente un mutex al principio y lo suelta cuando termina, o bloquea un mutex de una manera más inteligente en un nivel más fino, de modo que la contención del bloqueo es ¿reducido? Si de hecho lo hace de la segunda manera, ¿cómo lo hace?¿Cómo funciona malloc en un entorno multiproceso?

+0

¿Cuál es el contexto donde has visto eso? ¿Algún código o referencia entre comillas? – Raulp

+5

suavemente: estoy preguntando, sin decir nada. – pythonic

+0

Tengo que comentar que hay mejores alternativas a malloc cuando utilizo un entorno multihilo, use google –

Respuesta

35

glibc 2.15 opera la asignación múltiple arenas. Cada arena tiene su propio candado. Cuando un subproceso necesita asignar memoria, malloc() elige una arena, la bloquea y asigna memoria desde allí.

El mecanismo para la elección de un escenario es un tanto complicado y tiene como objetivo reducir la contención de bloqueo:

/* 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 esto en mente, malloc() básicamente se parece a esto (editado por brevedad):

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; 

Este asignador se llama ptmalloc. Se basa en earlier work por Doug Lea, y es mantenido por Wolfram Gloger.

19

Doug Lea's malloc utilizaba el bloqueo gruesa (o sin bloqueo, dependiendo de los ajustes de configuración), en el que cada llamada a malloc/realloc/free está protegido por un mutex global. Esto es seguro pero puede ser ineficiente en entornos altamente multiproceso.

ptmalloc3, que es la implementación predeterminada malloc en la biblioteca GNU C (libc) utilizado en la mayoría de los sistemas Linux en estos días, tiene una estrategia más de grano fino, como se describe en aix's answer, que permite que múltiples hilos para asignar simultáneamente memoria de forma segura .

nedmalloc es otra implementación independiente que asegura un rendimiento de subprocesos incluso mejor que ptmalloc3 y varios otros asignadores. No sé cómo funciona, y no parece haber ninguna documentación obvia, por lo que tendrá que verificar el código fuente para ver cómo funciona.

+1

Todavía estoy indeciso sobre si nedmalloc es una hazaña de ingeniería real o spam SEO ... :-) –

+0

también tcmalloc de google que utiliza bloqueos en cubos del tamaño de su solicitud. Mejor rendimiento de subprocesos con menos contención, más asignación excedente. –

+0

@R ..: Parece un poco sospechoso a primera vista, pero tiene un código fuente para que pueda compararlo usted mismo (no lo he hecho). Doug Lea también dice "Si está utilizando malloc en un programa simultáneo, considere usar nedmalloc o ptmalloc" en los comentarios de 'dlmalloc.c'. Entonces creo que es probablemente legítimo. –