Почему OSX-документ atoi/atof не является потокобезопасным?
Я понимаю, что strtol и strtof предпочтительнее atoi/atof, поскольку первые ошибки обнаружения, а также strtol гораздо более гибкие, чем atoi, когда речь идет о не-base-10.
Но мне все еще интересно что-то: "man atoi" (или atof) на OS X (хотя и не на Linux!) упоминает, что atoi/atof не являются потокобезопасными. Я, откровенно говоря, с трудом представляю возможную реализацию atoi или atof, которая не была бы потоковой. Кто-нибудь знает, почему эта страница говорит об этом? Действительно ли эти функции небезопасны для ОС X или любой другой платформы? И если они есть, то почему, возможно, библиотека не будет определять atoi с точки зрения strtol и, следовательно, быть в безопасности?
Ответы
Ответ 1
Взглянув на страницу руководства на MacOS X 10.6.6, он документирует две функции atof()
и atof_l()
, и я подозреваю, что дает подсказку о том, почему функция считается небезопасной:
СИНТАКСИС
#include <stdlib.h>
double atof(const char *str);
#include <xlocale.h>
double atof_l(const char *str, locale_t loc);
ОПИСАНИЕ
Функция atof()
преобразует начальную часть строки, на которую указывает str, для двойного представления.
Это эквивалентно:
strtod(str, (char **)NULL);
Символ десятичной точки определяется в локали программы (категория LC_NUMERIC).
В то время как функция atof()
использует текущую локаль, функция atof_l()
может быть передана локаль напрямую. Для получения дополнительной информации см. Xlocale (3).
ПРИМЕЧАНИЯ ОСУЩЕСТВЛЕНИЯ
Функция atof()
не является потокобезопасной, а также не безопасна для асинхронизации.
Функция atof()
устарела strtod()
и не должна использоваться в новом коде.
ОШИБКИ
Функция atof()
не должна влиять на значение errno
при ошибке.
Мое подозрение заключается в том, что если текущий язык изменяется другим потоком, а функция atof()
выполняется, результат не гарантируется. В противном случае, по-видимому, нет никаких оснований для предупреждения.
Я искал окончательное расположение исходного кода библиотеки Дарвина, но не нашел его. Если вы перейдете к исходному коду FreeBSD для atoi()
, то ясно, что реализация функции тривиальна:
int
atoi(str)
const char *str;
{
return (int)strtol(str, (char **)NULL, 10);
}
(Да, даже не используя прототипированное определение!)
Страница руководства для strtol()
не содержит ласковой формулировки о безопасности потоков или безопасности асинхронного отбраковки. Однако, быстрый взгляд на исходный код strtol()
показывает, что он использует isspace()
, на который влияет локаль:
ISO/IEC 9899: 1999, раздел 7.11.1.1 Функция setlocale
187 Единственные функции в 7.4, поведение которых не зависит от текущей локали, isdigit и isxdigit.
(где §7.4 для <ctype.h>
.)
Теперь, хотя я не уверен, что этот код идентичен тому, что в Дарвине (MacOS X), он, вероятно, будет похож. Я думаю, что на страницах руководства может быть место для ошибок: неясно, нужна ли страница, требующая коррекции, для atoi()
или для strtol()
.
Ответ 2
Здесь реализация atoi()
в Apple libc (atof()
похожа):
int
atoi(str)
const char *str;
{
return (int)strtol_l(str, (char **)NULL, 10, __current_locale());
}
И strtol()
:
long
strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
{
return strtol_l(nptr, endptr, base, __current_locale());
}
Так как man strtol не упоминает проблему безопасности потока с strtol()
, вы можете сделать один или несколько из нескольких выводов:
- Документы ошибочны в отношении
atoi()
, не связанных с потоком,
- они не обращают внимания на то, что
strtol()
также является небезопасным,
- они консервативны, документируя, что
atoi()
не дает обещания безопасности потоков, даже если текущая реализация оказывается потокобезопасной,
- они устарели (я полагаю, особый случай ошибочного).
__current_locale()
возвращает указатель на структуру, описывающую языковой стандарт потока (неудивительно). Однако, если языковой стандарт, зависящий от потока, не был установлен, __current_locale()
возвращает указатель на глобальную структуру локали. Я предположил, что использование глобального может быть небезопасным, но тогда этот вопрос будет применяться и к strtol()
.
Ответ 3
После некоторых исследований я считаю, что это просто наследие из старых дней, когда errno
была глобальной переменной. Если вы проверите FreeBSD errno.h
историю, начиная с первой ревизии, вы увидите, что он был первоначально определен как
extern int errno; /* global error number */
и теперь это функция. На самом деле я не могу думать о какой-либо другой причине.
Хотя atoi
всегда был оберткой вокруг strtol
, который также устанавливает errno
и должен иметь такую же безопасность потока. Это должна быть проблема с документацией.
Ответ 4
Этот ответ через пару лет после того, как вопрос был задан, и сначала ответил. На моей Mac OS X 10.8.3 (около марта 2013 года) man atoi
(или man atof
) читается:
IMPLEMENTATION NOTES
The atof() and atof_l() functions are thread-safe and async-cancel-safe.
The atof() and atof_l() functions have been deprecated by strtod() and
strtod_l() and should not be used in new code.
Таким образом, последнее слово, вероятно, заключается в том, что здесь никогда не было проблемы с обеспечением безопасности потоков, а только ошибки в документации.
Ответ 5
Предполагается, что эти функции не устанавливают errno в потоковом безопасном режиме, но это означает, что происходит что-то странное с errno на macos и thread. Обычно errno является локальной переменной потока.
Ответ 6
Предпосылка этого вопроса (в его первоначальном виде, до того, как я отредактировала заголовок) ошибочна. Они потокобезопасны. POSIX указывает, что все функции являются потокобезопасными, если не указано иное (POSIX), и в документации ничего не говорится об этих функциях, которые не являются потокобезопасными. OSX претендует на соответствие POSIX, поэтому они являются потокобезопасными на OSX, иначе это ошибка и большая проблема соответствия. Я собираюсь предположить, что это просто ошибка на страницах man...