Является ли malloc поточно-ориентированным? - PullRequest
68 голосов
/ 13 мая 2009

Является ли функция malloc() повторным входом?

Ответы [ 11 ]

95 голосов
/ 13 мая 2009

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

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

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

40 голосов
/ 13 мая 2009

Я где-то читал, что если вы скомпилируете с -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

9 голосов
/ 20 сентября 2010

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

Потокобезопасность: потокобезопасен, если не определено NO_THREADS

при условии, что NO_THREADS по умолчанию не определено, malloc является поточно-ориентированным по крайней мере в Linux.

8 голосов
/ 20 ноября 2014

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

Да, в настоящее время 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 голосов
/ 04 апреля 2015

Да, под POSIX.1-2008 malloc является потокобезопасным.

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

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

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

4 голосов
/ 17 марта 2017

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

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

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

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

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

Итак, если вы имеете в виду, «являются ли функции malloc () и free () поточно-безопасными», ответ - да. Но если вы имеете в виду, «весь malloc / free suite threadsafe», ответ НЕТ.

1 голос
/ 05 октября 2016

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

1 голос
/ 13 мая 2009

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

1 голос
/ 13 мая 2009

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

0 голосов
/ 13 августа 2018

Краткий ответ: да, начиная с C11, который является первой версией стандарта C, включающего концепцию потоков, malloc и его друзья должны быть поточно-ориентированными. Многие операционные системы, которые включали в себя как потоки, так и среду выполнения C, давали эту гарантию задолго до того, как это делал стандарт C, но я не готов поклясться all . Тем не менее, 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. И это то, что они сказали, возвращаясь к оригинальному 1989 стандарту ANSI C (этот документ имеет почти идентичную формулировку, но очень отличную нумерацию разделов от стандарта ISO C, который вышел в следующем году) :

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...