2012-05-22 4 views
42

Является ли типичный malloc (для платформы x86-64 и ОС Linux) наивно блокирует мьютекс в начале и освобождает его по завершении или блокирует мьютекс более умным способом на более тонком уровне, так что конфликт блокировки уменьшается? Если он действительно делает это вторым способом, как он это делает?Как работает malloc в многопоточной среде?

+0

Каков контекст, в котором вы видели это: любой цитируемый код или ссылку? – Raulp

+5

мягко: спрашиваю, не говорю. – pythonic

+0

Я должен прокомментировать, что есть много альтернатив malloc при использовании многопоточной среды, используйте google –

ответ

35

glibc 2.15 Управление несколькими распределениями arenas. Каждая арена имеет свой замок. Когда поток должен выделять память, malloc() выбирает арену, блокирует ее и выделяет из нее память.

Механизм выбора арены несколько сложный и направлен на снижение блокировок:

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

Имея это в виду, malloc() в основном выглядит следующим образом (отредактированный для краткости):

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; 

Этот распределитель называется ptmalloc. Он основан на earlier work Дугом Ли и поддерживается Вольфрамом Глогером.

19

Doug Lea's malloc используется грубый замок (или отсутствие блокировки, в зависимости от параметров конфигурации), где каждый вызов malloc/realloc/free защищен глобальной взаимной блокировкой. Это безопасно, но может быть неэффективным в многопоточных средах.

ptmalloc3, что реализация по умолчанию malloc в библиотеке GNU C (LIBC), используемой в большинстве систем Linux в эти дни, имеет более мелкозернистую стратегию, как описано в aix's answer, что позволяет несколько потоков одновременно выделить память безопасно ,

nedmalloc - это еще одна независимая реализация, которая утверждает, что даже более эффективная многопоточная производительность, чем ptmalloc3, и различные другие распределители. Я не знаю, как это работает, и, похоже, нет никакой очевидной документации, поэтому вам нужно будет проверить исходный код, чтобы увидеть, как он работает.

+1

Я все еще не уверен, что nedmalloc - настоящий инженерный подвиг или SEO-спам ... :-) –

+0

также tcmalloc из Google который использует блокировки на ведрах по вашему запросу. Лучшая производительность потока с меньшим количеством конкуренции, более избыточное распределение. –

+0

@R ..: На первый взгляд это выглядит немного подозрительно, но у него есть исходный код, поэтому вы можете сравнивать его самостоятельно (я этого не делал). Дуг Ли также говорит: «Если вы используете malloc в параллельной программе, рассмотрите вместо этого использование nedmalloc или ptmalloc» в комментариях для 'dlmalloc.c'. Поэтому я думаю, что это, вероятно, законно. –

Смежные вопросы