为什么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上是线程安全的,否则这是一个错误和主要的一致性问题。 我将假设它只是手册中的一个错误……