I understand that strtol and strtof are preferred to atoi/atof, since the former detect errors, and also strtol is much more flexible than atoi when it comes to non-base-10.
But I'm still curious about something: 'man atoi' (or atof) on OS X (though not on Linux!) mentions that atoi/atof are not threadsafe. I frankly have a hard time imagining a possible implementation of atoi or atof that would not be threadsafe. Does anybody know why the man page says this? Are these functions actually unsafe on OS X or any开发者_StackOverflow中文版 other platform? And if they are, why on earth wouldn't the library just define atoi in terms of strtol, and therefore be safe?
Taking a look at the manual page on MacOS X 10.6.6, it documents two functions, atof()
and atof_l()
, and I suspect that gives a hint as to why the function is deemed not thread-safe:
SYNOPSIS
#include <stdlib.h> double atof(const char *str); #include <xlocale.h> double atof_l(const char *str, locale_t loc);
DESCRIPTION
The
atof()
function converts the initial portion of the string pointed to by str to double representation.It is equivalent to:
strtod(str, (char **)NULL);
The decimal point character is defined in the program's locale (category LC_NUMERIC).
While the
atof()
function uses the current locale, theatof_l()
function may be passed a locale directly. See xlocale(3) for more information.IMPLEMENTATION NOTES
The
atof()
function is not thread-safe and also not async-cancel-safe.The
atof()
function has been deprecated bystrtod()
and should not be used in new code.ERRORS
The function
atof()
need not affect the value oferrno
on an error.
My suspicion is that if the current locale is changed by another thread while the atof()
function is executing, the result is not guaranteed. Otherwise, there seems to be no reason for the warning.
I've poked around for a definitive location of the Darwin C library source code, but have not found one. If you go to the FreeBSD source code for atoi()
, it is clear that the function implementation is trivial:
int
atoi(str)
const char *str;
{
return (int)strtol(str, (char **)NULL, 10);
}
(Yes, not even using a prototyped definition!)
The man page for strtol()
does not have the weasel wording about thread safety or async-cancel safety. However, a quick look at the source code for strtol()
shows that it uses isspace()
, which is affected by locale:
ISO/IEC 9899:1999, Section 7.11.1.1 The setlocale function
187 The only functions in 7.4 whose behavior is not affected by the current locale are isdigit and isxdigit.
(Where §7.4 is for <ctype.h>
.)
Now, while I'm not sure that this code is identical to what's in Darwin (MacOS X), it is likely to be similar. I think that there could be room for errata in the man pages - it is not so clear whether the page that needs correction is the one for atoi()
or the one for strtol()
.
After doing some research I think it's just legacy from the old days when errno
was a global variable. If you check FreeBSD errno.h
history starting from the first revision, you'd see that it was originally defined as
extern int errno; /* global error number */
and now it's a function. I cannot think of any other reason really.
Though atoi
always has been a wrapper around strtol
which also sets errno
and should then have the same thread safety. It must be just a documentation issue.
Here's the implementation of atoi()
in Apple's libc (atof()
is similar):
int
atoi(str)
const char *str;
{
return (int)strtol_l(str, (char **)NULL, 10, __current_locale());
}
And strtol()
:
long
strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
{
return strtol_l(nptr, endptr, base, __current_locale());
}
Since man strtol makes no mention of a thread-safety problem with strtol()
, you might draw one or more of several conclusions:
- the docs are wrong about
atoi()
being thread-unsafe, - they're neglecting to mention that
strtol()
is also thread unsafe, - they're being conservative by documenting that
atoi()
makes no promise of thread safety, even if the current implementation happens to be thread safe, - they're out of date (a special case of being wrong, I suppose)
__current_locale()
returns a pointer to a structure describing the thread's locale (unsurprisingly). However, if a thread-specific locale hasn't been set, __current_locale()
returns a pointer to a global locale structure. I supposed dealing with the global could be thread-unsafe, but then that issue would apply to strtol()
as well.
This answer is a couple of years after the question was asked, and first answered. On my Mac OS X 10.8.3 (circa March 2013), man atoi
(or man atof
) reads:
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.
So the final word is probably that there was never a thread-safety issue here, only errors in the documentation.
One guess is that these function do not set errno in a thread safe way, but that mean something strange is going on with errno on macos and thread. Normally errno is a thread local variable.
The premise of this question (in its original form, before I edited the title) is wrong. They are thread-safe. POSIX specifies that all functions are thread-safe unless otherwise documented (by POSIX), and the documentation does not say anything about these functions not being thread-safe. OSX purports to conform to POSIX, so they are thread-safe on OSX or else this is a bug and major conformance issue. I'm going to assume it's just a bug in the man pages...
精彩评论