Является ли malloc потокобезопасным?

Повторяется ли функция malloc()?

Ответ 1

Я где-то читал, что если вы компилируете с -pthread, malloc становится поточно-ориентированным. Я почти уверен, что его реализация зависит от того, что malloc - это ANSI C, а потоки - нет.

Если мы говорим о GCC:

Компиляция и связь с -pthread и malloc() будут поточно-ориентированными, на x86 и AMD64.

http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2431a99b9bdcef11/ea800579e40f7fa4

Другое мнение, более проницательное

{malloc, calloc, realloc, free, posix_memalign} из glibc-2. 2+ являются потокобезопасными

http://linux.derkeiler.com/Newsgroups/comp.os.linux.development.apps/2005-07/0323.html

Ответ 2

Вопрос: "Маллок реентрант"?
Ответ: нет, это не так. Вот одно из определений того, что делает рутинную реентерабельность.

Ни одна из распространенных версий malloc не позволяет повторно ввести его (например, из обработчика сигнала). Обратите внимание, что повторно входящая подпрограмма может не использовать блокировки, и почти во всех существующих версиях malloc используются блокировки (что делает их поточно-ориентированными) или глобальные/статические переменные (что делает их поточно-небезопасными и не реентерабельными).

На все ответы, которые до сих пор отвечали, является "malloc thread-safe?", Это совершенно другой вопрос. На этот вопрос ответ зависит от вашей библиотеки времени выполнения и, возможно, от используемых вами флагов компилятора. В любой современной UNIX вы получите поточно-ориентированный malloc по умолчанию. В Windows используйте флаги /MT, /MTd, /MD или /MDd чтобы получить поточно- /MDd библиотеку времени выполнения.

Ответ 3

Вот выдержка из malloc.c glibc:

Защита резьбы: поточно-безопасная, если не определено NO_THREADS

Предполагая, что NO_THREADS не определяется по умолчанию, malloc является потокобезопасным, по крайней мере, на linux.

Ответ 4

Это довольно старый вопрос, и я хочу привнести свежесть в соответствие с текущим положением вещей.

Да, в настоящее время malloc() является поточно-ориентированным.

Из Справочного руководства по библиотеке GNU C для glibc-2.20 [released 2014-09-07]:

void * malloc (size_t size)

Предварительно: MT-Safe |...

... 1.2.2.1 Концепции безопасности POSIX:

... MT-Safe или Thread-Safe функции безопасны для вызова при наличии других потоков. MT в MT-Safe означает Multi Thread.

Наличие MT-Safe не означает, что функция является атомарной, и что она не использует какой-либо из механизмов синхронизации памяти, которые POSIX предоставляет пользователям. Возможно даже, что последовательный вызов функций MT-Safe не приведет к комбинации MT-Safe. Например, наличие потока, вызывающего две функции MT-Safe, одна за другой, не гарантирует поведение, эквивалентное атомарному выполнению комбинации обеих функций, поскольку одновременные вызовы в других потоках могут мешать разрушительным образом.

Оптимизация всей программы, которая может встроить функции через интерфейсы библиотеки, может привести к небезопасному переупорядочению, поэтому выполнение встраивания через интерфейс библиотеки GNU C не рекомендуется. Документированное состояние MT-Safety не гарантируется при оптимизации программы. Однако функции, определенные в видимых пользователем заголовках, разработаны для обеспечения безопасности при встраивании.

Ответ 5

Да, под POSIX.1-2008 malloc является поточно-ориентированным.

2.9.1 Потокобезопасность

Все функции, определенные этим томом POSIX.1-2008, должны быть поточно-ориентированными, за исключением того, что следующие функции1 не обязательно должны быть поточно-ориентированными.

[список функций, которые не содержат malloc ]

Ответ 6

Если вы работаете с GLIBC, ответ: Да, НО.

В частности, да, НО, пожалуйста, имейте в виду, что в то время как malloc и free являются потокобезопасными, функции отладки не являются.

В частности, чрезвычайно полезные функции mtrace(), mcheck() и mprobe() не являются потокобезопасными. В одном из кратчайших, прямых ответов, которые вы когда-либо увидите из проекта GNU, это объясняется здесь:

https://sourceware.org/bugzilla/show_bug.cgi?id=9939

Вам понадобятся альтернативные методы, такие как ElectricFence, valgrind, dmalloc и т.д.

Итак, если вы имеете в виду, "являются функциями malloc() и free() threadsafe", то да. Но если вы имеете в виду, "это весь malloc/free suite threadsafe", ответ НЕТ.

Ответ 7

Это зависит от того, какую реализацию используемой библиотеки времени выполнения C вы используете. Например, если вы используете MSVC, то есть опция компилятора, которая позволяет указать, какую версию библиотеки вы хотите построить (например, библиотеку времени выполнения, которая поддерживает многопоточность, будучи защищенной от протектора или нет).

Ответ 8

Нет, он не является потокобезопасным. На самом деле может быть функция malloc_lock() и malloc_unlock(), доступная в вашей библиотеке C. Я знаю, что они существуют для библиотеки Newlib. Мне пришлось использовать это для реализации мьютекса для моего процессора, который многопоточен в аппаратном обеспечении.

Ответ 9

malloc и free не являются реентерабельными, поскольку они используют статическую структуру данных, которая записывает, какие блоки памяти свободны. В результате никакие функции библиотеки, которые выделяют или не освобождают память, являются реентерабельными.

Ответ 11

Краткий ответ: да, начиная с C11, который является первой версией стандарта C, который включает в себя концепцию потоков, malloc и friends должны быть поточно-ориентированными. Многие операционные системы, которые включали в себя как потоки, так и среду выполнения C, давали эту гарантию задолго до того, как это делал стандарт C, но я не готов клясться на всех. Однако malloc и друзья не являются и никогда не должны были возвращаться.

Это означает, что безопасно вызывать malloc и одновременно free несколько потоков и не беспокоиться о блокировке, если вы не нарушаете другие правила распределения памяти (например, вызов free один раз и только один раз для каждого указателя, возвращаемого malloc). Но небезопасно вызывать эти функции из обработчика сигнала, который мог прервать вызов malloc или free поток, обрабатывающий сигнал. Иногда, используя функциональность за пределами ISO C, вы можете гарантировать, что поток, обрабатывающий сигнал, не прервал вызов malloc или free, например, с помощью sigprocmask и sigpause, но попытайтесь этого не делать, если у вас нет другой опции, потому что трудно получить совершенно правильно.


Длинный ответ с цитатами: Стандарт C добавил концепцию потоков в редакции 2011 года (ссылка на документ N1570, который является наиболее близким приближением к официальному тексту стандарта 2011 года, который доступен для общественности бесплатно). В этом пересмотре в разделе 7.1.4 параграфа 5 говорится:

Если явно не указано иное в подробных описаниях, которые следуют, библиотечные функции должны предотвращать гонки данных следующим образом: библиотечная функция не должна прямо или косвенно обращаться к объектам, доступным для потоков, отличных от текущего потока, если к объектам не осуществляется прямой или косвенный доступ через аргументы функции, Библиотечная функция не должна прямо или косвенно изменять объекты, доступные для потоков, отличных от текущего потока, если к объектам не обращаются напрямую или косвенно через неконстантные аргументы функции. Реализации могут делиться своими внутренними объектами между потоками, если эти объекты не видны пользователям и защищены от скачек данных.

[сноска: это означает, например, что реализации не разрешается использовать статический объект для внутренних целей без синхронизации, потому что это может вызвать гонку данных даже в программах, которые не разделяют объекты явно между потоками. Точно так же реализация memcpy не позволяет копировать байты сверх указанной длины целевого объекта, а затем восстанавливать исходные значения, потому что это может вызвать гонку данных, если программа поделила эти байты между потоками.]

Насколько я понимаю, это многословный способ сказать, что библиотечные функции, определенные стандартом C, должны быть поточно-ориентированными (в обычном смысле: вы можете вызывать их из нескольких потоков одновременно, не блокируя себя самостоятельно). до тех пор, пока они не столкнутся с конфликтом данных, передаваемых в качестве аргументов), если в документации по конкретной функции не указано, что это не так.

Затем 7.22.3p2 подтверждает, что malloc, calloc, realloc, align_alloc и free, в частности, являются поточно-ориентированными:

В целях определения существования гонки данных функции выделения памяти ведут себя так, как будто они обращаются только к тем ячейкам памяти, которые доступны через их аргументы, а не к другой статической памяти хранения. Эти функции могут, однако, визуально изменять хранилище, которое они выделяют или освобождают. Вызов free или realloc, который освобождает область p памяти, синхронизируется с любым вызовом выделения, который выделяет всю или часть области p. Эта синхронизация происходит после любого доступа к p с помощью функции освобождения и перед любым таким доступом с помощью функции распределения.

Сравните то, что говорится о strtok, который не является и никогда не был поточно- ориентированным, в 7.24.5.8p6:

Функция strtok не требуется, чтобы избежать скачек данных при других вызовах функции strtok.

[сноска: вместо этого можно использовать функцию strtok_s, чтобы избежать скачек данных.]

(прокомментируйте сноску: не используйте strtok_s, используйте strsep.)

Более старые версии стандарта C ничего не говорили о безопасности потоков. Тем не менее, они что-то говорили о повторном входе, потому что сигналы всегда были частью стандарта C. И это то, что они сказали, возвращаясь к первоначальному стандарту ANSI C 1989 года (этот документ имеет почти идентичную формулировку, но очень отличную нумерацию разделов от стандарта ISO C, который вышел в следующем году):

Если сигнал [a] возникает иначе, чем в результате вызова функции отмены или повышения, поведение не определено, если обработчик сигнала вызывает какую-либо функцию в стандартной библиотеке, кроме самой функции сигнала, или ссылается на любой объект со статической продолжительностью хранения, другой чем путем присвоения значения статической переменной продолжительности хранения типа volatile sig_atomic_t. Кроме того, если такой вызов функции сигнала приводит к возврату SIG_ERR, значение errno является неопределенным.

Который является многословным способом сказать, что функции библиотеки C не обязаны повторно входить как общее правило. Очень похожая формулировка все еще появляется в C11, 7.14.1.1p5:

Если сигнал [a] возникает не в результате вызова функции отмены или повышения, поведение не определено, если обработчик сигнала ссылается на какой-либо объект со статическим или потоковым сроком хранения, который не является атомарным объектом без блокировки, кроме как путем назначения значение объекта, объявленного как volatile sig_atomic_t, или обработчик сигнала вызывает любую функцию в стандартной библиотеке, кроме функции прерывания, функции _Exit, функции quick_exit или функции сигнала, первый аргумент которого равен номеру сигнала, соответствующему сигнал, вызвавший вызов обработчика. Кроме того, если такой вызов функции сигнала приводит к возврату SIG_ERR, значение errno является неопределенным.

[сноска: если какой-либо сигнал генерируется асинхронным обработчиком сигнала, поведение не определено.]

POSIX требует гораздо более длинного, но все еще короткого по сравнению с общим размером библиотеки C списка функций, которые можно безопасно вызывать из "обработчика асинхронного сигнала", а также более детально определяет обстоятельства, при которых сигнал может "возникать" чем в результате вызова функции отмены или повышения. " Если вы делаете что-то нетривиальное с сигналами, вы, вероятно, пишете код, предназначенный для запуска в ОС с природой Unix (в отличие от Windows, MVS или чего-то встроенного, что, вероятно, не имеет полной размещенной реализации C в первое место), и вы должны ознакомиться с требованиями POSIX к ним, а также требованиями ISO C.