为什么OSX将atoi / atof记录为不是线程安全的?
我知道strtol和strtof比atoi / atof更受欢迎,因为前者检测错误,而且当涉及非base-10时,strtol比atoi更灵活。
但我仍然对某些事情感到好奇:OS X上的’man atoi’(或atof)(虽然不在Linux上!)提到atoi / atof不是线程安全的。 坦率地说,我很难想象atoi或atof的可能实现是不会线程安全的。 有人知道为什么手册页会这么说吗? 这些function在OS X或任何其他平台上实际上是不安全的吗? 如果它们是,那么为什么图书馆不会根据strtol定义atoi,因此是安全的?
看一下MacOS X 10.6.6上的手册页,它记录了两个函数, atof()
和atof_l()
,我怀疑它提供了一个关于为什么函数被认为不是线程安全的提示:
概要
#include
double atof(const char *str); #include double atof_l(const char *str, locale_t loc); 描述
atof()
函数将str指向的字符串的初始部分转换为double表示。它相当于:
strtod(str, (char **)NULL);
小数点字符在程序的语言环境中定义(类别LC_NUMERIC)。
虽然
atof()
函数使用当前语言环境,但atof_l()
函数可以直接传递给语言环境。 有关更多信息,请参见xlocale(3)。实施说明
atof()
函数不是线程安全的,也不是async-cancel-safe。
atof()
已弃用atof()
函数,不应在新代码中使用。错误
函数
atof()
不需要影响错误的errno
值。
我怀疑如果在执行atof()
函数时当前语言环境被另一个线程更改,则无法保证结果。 否则,似乎没有理由发出警告。
我已经探到了Darwin C库源代码的确切位置,但还没找到。 如果你转到atoi()
的FreeBSD源代码,很明显函数实现是微不足道的:
int atoi(str) const char *str; { return (int)strtol(str, (char **)NULL, 10); }
(是的,甚至没有使用原型定义!)
strtol()
的手册页没有关于线程安全或异步取消安全的黄鼠狼措辞。 但是,快速查看strtol()
的源代码表明它使用了受locale影响的isspace()
:
ISO / IEC 9899:1999,第7.11.1.1节setlocale函数
187 7.4中唯一不受当前语言环境影响的函数是isdigit和isxdigit。
(其中§7.4适用于
。)
现在,虽然我不确定这段代码是否与达尔文(MacOS X)中的代码相同,但它可能类似。 我认为在手册页中可能存在勘误的空间 – 不太清楚需要更正的页面是atoi()
还是strtol()
。
这是 Apple的libc中atoi()
的实现 ( 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()
。
在做了一些研究之后,我认为这只是过去,当时errno
是一个全局变量。 如果您从第一个修订版开始检查FreeBSD errno.h
历史记录 ,您会看到它最初定义为
extern int errno; /* global error number */
现在它是一个function。 我真的想不出任何其他原因。
虽然atoi
一直是strtol
的包装器,它也设置了errno
,然后应该具有相同的线程安全性。 它必须只是一个文档问题。
这个答案是在提出问题后的几年,并首先回答。 在我的Mac OS X 10.8.3(大约2013年3月)上, 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.
所以最后一句话可能是这里从来没有线程安全问题,只有文档中的错误。
一个猜测是这些函数没有以线程安全的方式设置errno,但这意味着在macos和线程上使用errno会发生一些奇怪的事情。 通常,errno是一个线程局部变量。
这个问题的前提(在我编辑标题之前的原始forms)是错误的。 它们是线程安全的。 除非另有说明(POSIX),否则POSIX指定所有函数都是线程安全的,并且文档没有说明这些函数不是线程安全的。 OSX声称符合POSIX,因此它们在OSX上是线程安全的,否则这是一个错误和主要的一致性问题。 我将假设它只是手册中的一个错误……