2012-05-22 5 views
42

Ist die typische malloc (für x86-64-Plattform und Linux OS) naiv sperren einen Mutex am Anfang und veröffentlichen Sie es, wenn Sie fertig sind, oder ein Mutex auf eine cleverere Weise auf eine feinere Ebene sperren, so dass Sperrenkonflikt ist reduziert? Wenn es das tatsächlich auf die zweite Art macht, wie macht es das?Wie funktioniert Malloc in einer Multithread-Umgebung?

+0

In welchem ​​Kontext haben Sie diesen Code oder Referenzcode gesehen? – Raulp

+5

leise: Ich frage, nicht zu sagen. – pythonic

+0

Ich muss kommentieren, dass es bessere Alternativen zu malloc gibt, wenn man eine multi-threaded Umgebung benutzt, google –

Antwort

35

glibc 2.15 arbeitet mehrere Zuordnung Arenen. Jede Arena hat ihr eigenes Schloss. Wenn ein Thread Speicher reservieren muss, wählt malloc() eine Arena aus, sperrt sie und weist ihr Speicher zu.

Der Mechanismus eine Arena für die Wahl ein wenig aufwendig ist und zur Verringerung der Sperrkonflikte Ziel:

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

dies mit im Auge, wie diese malloc() im Grunde (der Kürze halber bearbeitet) aussieht:

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; 

Dieser Zuordner heißt ptmalloc. Es basiert auf earlier work von Doug Lea und wird von Wolfram Gloger gepflegt.

19

Doug Lea's malloc verwendete grobe Verriegelung (oder keine Verriegelung, von den Konfigurationseinstellungen abhängig), wobei jeder Anruf zu malloc/realloc/free durch ein globales Mutex geschützt ist. Dies ist sicher, kann jedoch in Umgebungen mit hohem Multithread-Aufwand ineffizient sein.

ptmalloc3, die die Standard-malloc Implementierung in der GNU C-Bibliothek (libc) verwendet, auf den meisten Linux-Systeme in diesen Tagen, hat eine feinkörnigere Strategie, wie in aix's answer beschrieben, das gleichzeitig mehrere Threads ermöglicht Speicher sicher zuzuteilen .

nedmalloc ist eine weitere unabhängige Implementierung, die eine noch bessere Multithreading-Leistung als ptmalloc3 und verschiedene andere Zuweiser beansprucht. Ich weiß nicht, wie es funktioniert, und es scheint keine offensichtliche Dokumentation zu geben, also müssen Sie den Quellcode überprüfen, um zu sehen, wie es funktioniert.

+1

Ich bin immer noch unentschlossen, ob nedmalloc eine echte technische Meisterleistung oder SEO Spam ist ... :-) –

+0

auch tcmalloc von google Dies verwendet Sperren für Buckets, die Ihrer Anfrage entsprechen. Bessere Thread-Performance mit weniger Contention, mehr Überschuss-Zuweisung. –

+0

@R ..: Es sieht ein wenig verdächtig auf den ersten Blick, aber es hat Quellcode, so dass Sie es selbst benchmarken können (ich habe es nicht getan). Doug Lea sagt auch: "Wenn Sie malloc in einem parallelen Programm verwenden, sollten Sie stattdessen nedmalloc oder ptmalloc verwenden" in den Kommentaren für 'dlmalloc.c'. Also ich denke es ist wahrscheinlich echt. –