49 votes

Comment malloc travailler dans un environnement multithread?

Le typique malloc (pour x86-64 plate-forme et système d'exploitation Linux) naïvement verrouiller un mutex au début et relâchez lorsque vous avez terminé, ou est-il verrouiller un mutex de façon plus intelligente plus fine, de niveau, de sorte que le verrouillage est réduit? Si en effet, il en fait la deuxième façon, comment fait-il cela?

39voto

NPE Points 169956

glibc 2.15 gère plusieurs d'allocation des arènes. Chaque domaine a son propre cadenas. Lorsqu'un thread a besoin d'allouer de la mémoire, malloc() choisit une arène, qu'il se bloque, et alloue de la mémoire à partir d'elle.

Le mécanisme pour le choix d'une arène est quelque peu complexe, et vise à réduire de verrouillage:

/* 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. */

Avec cela à l'esprit, malloc() ressemble fondamentalement à ce (édité par souci de concision):

  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;

Cet allocateur est appelé ptmalloc. Il est basé sur des travaux antérieurs par Doug Lea, et est maintenu par Wolfram Gloger.

21voto

Adam Rosenfield Points 176408

Doug Lea malloc utilisé grossier de verrouillage (ou pas de verrouillage, selon les paramètres de configuration), où chaque appel à l' malloc/realloc/free est protégée par un mutex. C'est sûr, mais peut être inefficace dans la très multithread environnements.

ptmalloc3, ce qui est la valeur par défaut malloc mise en œuvre dans la bibliothèque GNU C (libc) utilisé sur la plupart des systèmes Linux ces jours-ci, a une plus fine de la stratégie, comme décrit dans aix réponse, ce qui permet à plusieurs threads simultanément allouer de la mémoire en toute sécurité.

nedmalloc est un autre indépendant de la mise en œuvre qui revendique même mieux multithread performances qu' ptmalloc3 et divers autres allocateurs. Je ne sais pas comment cela fonctionne, et il ne semble pas du tout évident de documentation, de sorte que vous aurez à vérifier le code source pour voir comment il fonctionne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X